1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-28 21:06:50 +01:00

Fossil Hybrid HR: Use preferencescreen for widget configuration

This commit is contained in:
Arjan Schrijver 2022-07-22 12:28:19 +02:00
parent 3e6d2bd40e
commit c946a045ef
8 changed files with 484 additions and 410 deletions

View File

@ -678,6 +678,10 @@
android:name=".devices.qhybrid.HybridHRWatchfaceSettingsActivity"
android:label="@string/watchface_dialog_title_settings"
android:parentActivityName=".devices.qhybrid.HybridHRWatchfaceDesignerActivity" />
<activity
android:name=".devices.qhybrid.HybridHRWatchfaceWidgetActivity"
android:label="@string/watchface_dialog_title_widget"
android:parentActivityName=".devices.qhybrid.HybridHRWatchfaceDesignerActivity" />
<activity
android:name=".devices.um25.Activity.DataActivity"

View File

@ -101,6 +101,7 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
private final int CHILD_ACTIVITY_IMAGE_CHOOSER = 0;
private final int CHILD_ACTIVITY_SETTINGS = 1;
private final int CHILD_ACTIVITY_WIDGET = 2;
BroadcastReceiver fileUploadReceiver = new BroadcastReceiver() {
@Override
@ -181,6 +182,15 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
renderWatchfacePreview();
} else if (requestCode == CHILD_ACTIVITY_SETTINGS && resultCode == Activity.RESULT_OK && resultData != null) {
watchfaceSettings = (HybridHRWatchfaceSettings) resultData.getSerializableExtra("watchfaceSettings");
} else if (requestCode == CHILD_ACTIVITY_WIDGET && resultCode == Activity.RESULT_OK && resultData != null) {
int widgetIndex = (int) resultData.getSerializableExtra("widgetIndex");
HybridHRWatchfaceWidget editedWidget = (HybridHRWatchfaceWidget) resultData.getSerializableExtra("widgetSettings");
if (widgetIndex >= 0) {
widgets.set(widgetIndex, editedWidget);
} else {
widgets.add(editedWidget);
}
renderWatchfacePreview();
}
}
@ -478,227 +488,30 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
backgroundImageView.setImageBitmap(processedBackgroundImage);
}
private void showWidgetEditPopup(final int index) {
View layout = getLayoutInflater().inflate(R.layout.dialog_hybridhr_watchface_widget, null);
HybridHRWatchfaceWidget widget = null;
private void showWidgetEditPopup(int index) {
HybridHRWatchfaceWidget widget;
if (index >= 0) {
widget = widgets.get(index);
}
// Configure widget type dropdown
final Spinner typeSpinner = layout.findViewById(R.id.watchface_widget_type_spinner);
LinkedHashMap<String, String> widgetTypes = HybridHRWatchfaceWidget.getAvailableWidgetTypes(this);
ArrayAdapter<String> widgetTypeAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, widgetTypes.values().toArray(new String[0]));
typeSpinner.setAdapter(widgetTypeAdapter);
final ArrayList<String> widgetTypesArray = new ArrayList<>(widgetTypes.keySet());
if ((widget != null) && (widgetTypesArray.contains(widget.getWidgetType()))) {
typeSpinner.setSelection(widgetTypesArray.indexOf(widget.getWidgetType()));
}
// Configure widget color dropdown
final Spinner colorSpinner = layout.findViewById(R.id.watchface_widget_color_spinner);
ArrayAdapter<String> widgetColorAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, new String[]{getString(R.string.watchface_dialog_widget_color_white), getString(R.string.watchface_dialog_widget_color_black)});
colorSpinner.setAdapter(widgetColorAdapter);
if (widget != null) {
colorSpinner.setSelection(widget.getColor());
} else {
colorSpinner.setSelection(defaultWidgetColor);
}
// Set X coordinate
final EditText posX = layout.findViewById(R.id.watchface_widget_pos_x);
if (widget != null) {
posX.setText(Integer.toString(widget.getPosX()));
}
// Set Y coordinate
final EditText posY = layout.findViewById(R.id.watchface_widget_pos_y);
if (widget != null) {
posY.setText(Integer.toString(widget.getPosY()));
}
class WidgetPosition{
final int posX, posY, buttonResource, hintStringResource;
public WidgetPosition(int posX, int posY, int buttonResource, int hintStringResource) {
this.posX = posX;
this.posY = posY;
this.buttonResource = buttonResource;
this.hintStringResource = hintStringResource;
}
}
WidgetPosition[] positions = new WidgetPosition[]{
new WidgetPosition(120, 58, R.id.watchface_widget_preset_top, R.string.watchface_dialog_widget_preset_top),
new WidgetPosition(182, 120, R.id.watchface_widget_preset_right, R.string.watchface_dialog_widget_preset_right),
new WidgetPosition(120, 182, R.id.watchface_widget_preset_bottom, R.string.watchface_dialog_widget_preset_bottom),
new WidgetPosition(58, 120, R.id.watchface_widget_preset_left, R.string.watchface_dialog_widget_preset_left),
};
for(final WidgetPosition position : positions){
Button btn = layout.findViewById(position.buttonResource);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
posX.setText(String.valueOf(position.posX));
posY.setText(String.valueOf(position.posY));
}
});
}
if(widget == null){
int posX = 120;
int posY = 120;
int currentIndex = widgets.size();
if(currentIndex < 4){
WidgetPosition newPosition = positions[currentIndex];
posX.setText(String.valueOf(newPosition.posX));
posY.setText(String.valueOf(newPosition.posY));
if (currentIndex < 4) {
HybridHRWidgetPosition newPosition = HybridHRWatchfaceWidget.defaultPositions[currentIndex];
posX = newPosition.posX;
posY = newPosition.posY;
GB.toast(getString(R.string.watchface_dialog_pre_setting_position, getString(newPosition.hintStringResource)), Toast.LENGTH_SHORT, GB.INFO);
}
}
// Set widget size
final LinearLayout sizeLayout = layout.findViewById(R.id.watchface_widget_size_layout);
sizeLayout.setVisibility(View.GONE);
final EditText widgetWidth = layout.findViewById(R.id.watchface_widget_width);
if ((widget != null) && (widget.getWidth() >= 0)) {
widgetWidth.setText(Integer.toString(widget.getWidth()));
}
// Populate timezone spinner
String[] timezonesList = TimeZone.getAvailableIDs();
final Spinner tzSpinner = layout.findViewById(R.id.watchface_widget_timezone_spinner);
final LinearLayout timezoneLayout = layout.findViewById(R.id.watchface_widget_timezone_layout);
timezoneLayout.setVisibility(View.GONE);
ArrayAdapter<String> widgetTZAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, timezonesList);
tzSpinner.setAdapter(widgetTZAdapter);
if (widget != null) {
tzSpinner.setSelection(Arrays.asList(timezonesList).indexOf(widget.getExtraConfigString("tzName", "Etc/UTC")));
} else {
tzSpinner.setSelection(Arrays.asList(timezonesList).indexOf("Etc/UTC"));
}
// Set timezone clock timeout
final LinearLayout timezoneTimeoutLayout = layout.findViewById(R.id.watchface_widget_timezone_timeout_layout);
timezoneTimeoutLayout.setVisibility(View.GONE);
final EditText timezoneTimeout = layout.findViewById(R.id.watchface_widget_timezone_timeout);
if ((widget != null) && (widget.getExtraConfigInt("timeout_secs", -1) >= 0)) {
timezoneTimeout.setText(Integer.toString(widget.getExtraConfigInt("timeout_secs", -1)));
}
// Set update timeout value
final LinearLayout updateTimeoutLayout = layout.findViewById(R.id.watchface_widget_update_timeout_layout);
updateTimeoutLayout.setVisibility(View.GONE);
final EditText updateTimeout = layout.findViewById(R.id.watchface_widget_update_timeout);
if ((widget != null) && (widget.getExtraConfigInt("update_timeout", -1) > 0)) {
updateTimeout.setText(Integer.toString(widget.getExtraConfigInt("update_timeout", -1)));
}
final CheckBox timeoutHideText = layout.findViewById(R.id.watchface_widget_timeout_hide_text);
if (widget != null) {
timeoutHideText.setChecked(widget.getExtraConfigBoolean("timeout_hide_text", true));
}
final CheckBox timeoutShowCircle = layout.findViewById(R.id.watchface_widget_timeout_show_circle);
if (widget != null) {
timeoutShowCircle.setChecked(widget.getExtraConfigBoolean("timeout_show_circle", true));
}
// Show certain input fields only when the relevant TZ widget is selected
typeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String selectedType = widgetTypesArray.get(typeSpinner.getSelectedItemPosition());
if (selectedType.equals("widget2ndTZ")) {
timezoneLayout.setVisibility(View.VISIBLE);
timezoneTimeoutLayout.setVisibility(View.VISIBLE);
} else {
timezoneLayout.setVisibility(View.GONE);
timezoneTimeoutLayout.setVisibility(View.GONE);
}
if (selectedType.equals("widgetCustom")) {
sizeLayout.setVisibility(View.VISIBLE);
updateTimeoutLayout.setVisibility(View.VISIBLE);
} else {
sizeLayout.setVisibility(View.GONE);
updateTimeoutLayout.setVisibility(View.GONE);
}
int color = 0;
if (widgets.size() > 0) {
color = widgets.get(0).getColor();
}
@Override
public void onNothingSelected(AdapterView<?> parent) { }
});
// Show dialog
new AlertDialog.Builder(this)
.setView(layout)
.setNegativeButton(R.string.fossil_hr_edit_action_delete, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (index >= 0) {
widgets.remove(index);
renderWatchfacePreview();
}
}
})
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int selectedPosX;
int selectedPosY;
try {
selectedPosX = Integer.parseInt(posX.getText().toString());
selectedPosY = Integer.parseInt(posY.getText().toString());
} catch (NumberFormatException e) {
GB.toast(getString(R.string.watchface_toast_settings_incomplete), Toast.LENGTH_SHORT, GB.WARN);
LOG.warn("Error parsing input", e);
return;
}
if (selectedPosX < 1) selectedPosX = 1;
if (selectedPosX > 240) selectedPosX = 240;
if (selectedPosY < 1) selectedPosY = 1;
if (selectedPosY > 240) selectedPosY = 240;
int selectedWidth = 76;
try {
selectedWidth = Integer.parseInt(widgetWidth.getText().toString());
} catch (NumberFormatException e) {
LOG.warn("Error parsing input", e);
}
String selectedType = widgetTypesArray.get(typeSpinner.getSelectedItemPosition());
String selectedTZ = tzSpinner.getSelectedItem().toString();
int selectedTZtimeout = Integer.parseInt(timezoneTimeout.getText().toString());
int selectedUpdateTimeout = 0;
if (selectedType.equals("widgetCustom")) {
try {
selectedUpdateTimeout = Integer.parseInt(updateTimeout.getText().toString());
} catch (NumberFormatException e) {
GB.toast(getString(R.string.watchface_toast_settings_incomplete), Toast.LENGTH_SHORT, GB.WARN);
LOG.warn("Error parsing input", e);
return;
}
}
boolean selectedTimeoutHideText = timeoutHideText.isChecked();
boolean selectedTimeoutShowCircle = timeoutShowCircle.isChecked();
HybridHRWatchfaceWidget widgetConfig;
if (selectedType.equals("widget2ndTZ")) {
JSONObject extraConfig = new JSONObject();
try {
extraConfig.put("tzName", selectedTZ);
extraConfig.put("timeout_secs", selectedTZtimeout);
} catch (JSONException e) {
LOG.warn("JSON error", e);
}
widgetConfig = new HybridHRWatchfaceWidget(selectedType, selectedPosX, selectedPosY, 76, 76, colorSpinner.getSelectedItemPosition(), extraConfig);
} else if (selectedType.equals("widgetCustom")) {
JSONObject extraConfig = new JSONObject();
try {
extraConfig.put("update_timeout", selectedUpdateTimeout);
extraConfig.put("timeout_hide_text", selectedTimeoutHideText);
extraConfig.put("timeout_show_circle", selectedTimeoutShowCircle);
} catch (JSONException e) {
LOG.warn("JSON error", e);
}
widgetConfig = new HybridHRWatchfaceWidget(selectedType, selectedPosX, selectedPosY, selectedWidth, 76, colorSpinner.getSelectedItemPosition(), extraConfig);
} else {
widgetConfig = new HybridHRWatchfaceWidget(selectedType, selectedPosX, selectedPosY, 76, 76, colorSpinner.getSelectedItemPosition(), null);
}
if (index >= 0) {
widgets.set(index, widgetConfig);
} else {
widgets.add(widgetConfig);
}
renderWatchfacePreview();
}
})
.setTitle(R.string.watchface_dialog_title_add_widget)
.show();
widget = new HybridHRWatchfaceWidget("widgetDate", posX, posY, 76, 76, color, null);
}
Intent intent = new Intent(this, HybridHRWatchfaceWidgetActivity.class);
intent.putExtra("widgetIndex", index);
intent.putExtra("widgetSettings", widget);
startActivityForResult(intent, CHILD_ACTIVITY_WIDGET);
}
private void showWatchfaceSettingsPopup() {
@ -771,7 +584,7 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
public void run() {
GBApplication.deviceService().onAppDelete(UUID.nameUUIDFromBytes("previewWatchface".getBytes(StandardCharsets.UTF_8)));
}
}, 10000);
}, 15000);
} else {
readyToCloseActivity = true;
final FossilFileReader fossilFile = new FossilFileReader(tempAppFileUri, this);

View File

@ -20,28 +20,35 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import org.json.JSONObject;
import java.io.IOException;
import java.io.Serializable;
import java.util.LinkedHashMap;
import nodomain.freeyourgadget.gadgetbridge.R;
import static nodomain.freeyourgadget.gadgetbridge.util.BitmapUtil.invertBitmapColors;
import org.json.JSONException;
import org.json.JSONObject;
public class HybridHRWatchfaceWidget {
public class HybridHRWatchfaceWidget implements Serializable {
private String widgetType;
private int posX;
private int posY;
private int width;
private int height;
private int color;
private JSONObject extraConfig;
private String extraConfigJSON;
public static int COLOR_WHITE = 0;
public static int COLOR_BLACK = 1;
static HybridHRWidgetPosition[] defaultPositions = new HybridHRWidgetPosition[]{
new HybridHRWidgetPosition(120, 58, R.string.watchface_dialog_widget_preset_top),
new HybridHRWidgetPosition(182, 120, R.string.watchface_dialog_widget_preset_right),
new HybridHRWidgetPosition(120, 182, R.string.watchface_dialog_widget_preset_bottom),
new HybridHRWidgetPosition(58, 120, R.string.watchface_dialog_widget_preset_left),
};
public HybridHRWatchfaceWidget(String widgetType, int posX, int posY, int width, int height, int color, JSONObject extraConfig) {
this.widgetType = widgetType;
this.posX = posX;
@ -49,7 +56,11 @@ public class HybridHRWatchfaceWidget {
this.width = width;
this.height = height;
this.color = color;
this.extraConfig = extraConfig;
try {
this.extraConfigJSON = extraConfig.toString();
} catch (Exception e) {
this.extraConfigJSON = "{}";
}
}
public static LinkedHashMap<String, String> getAvailableWidgetTypes(Context context) {
@ -67,10 +78,14 @@ public class HybridHRWatchfaceWidget {
return widgetTypes;
}
public void setWidgetType(String widgetType) {
this.widgetType = widgetType;
}
public String getWidgetType() {
return widgetType;
}
public Bitmap getPreviewImage(Context context) throws IOException {
Bitmap preview = BitmapFactory.decodeStream(context.getAssets().open("fossil_hr/" + widgetType + "_preview.png"));
if (color == COLOR_WHITE) {
@ -116,24 +131,67 @@ public class HybridHRWatchfaceWidget {
}
public int getExtraConfigInt(String name, int fallback) {
if (extraConfig == null) {
try {
return new JSONObject(extraConfigJSON).optInt(name, fallback);
} catch (Exception e) {
return fallback;
} else {
return extraConfig.optInt(name, fallback);
}
}
public String getExtraConfigString(String name, String fallback) {
if (extraConfig == null) {
try {
return new JSONObject(extraConfigJSON).optString(name, fallback);
} catch (Exception e) {
return fallback;
} else {
return extraConfig.optString(name, fallback);
}
}
public Boolean getExtraConfigBoolean(String name, Boolean fallback) {
if (extraConfig == null) {
try {
return new JSONObject(extraConfigJSON).optBoolean(name, fallback);
} catch (Exception e) {
return fallback;
} else {
return extraConfig.optBoolean(name, fallback);
}
}
public void setExtraConfigInt(String name, int value) {
JSONObject extraConfig;
try {
extraConfig = new JSONObject(extraConfigJSON);
} catch (Exception e) {
extraConfig = new JSONObject();
}
try {
extraConfig.put(name, value);
extraConfigJSON = extraConfig.toString();
} catch (Exception e) {
return;
}
}
public void setExtraConfigString(String name, String value) {
JSONObject extraConfig;
try {
extraConfig = new JSONObject(extraConfigJSON);
} catch (Exception e) {
extraConfig = new JSONObject();
}
try {
extraConfig.put(name, value);
extraConfigJSON = extraConfig.toString();
} catch (Exception e) {
return;
}
}
public void setExtraConfigBoolean(String name, Boolean value) {
JSONObject extraConfig;
try {
extraConfig = new JSONObject(extraConfigJSON);
} catch (Exception e) {
extraConfig = new JSONObject();
}
try {
extraConfig.put(name, value);
extraConfigJSON = extraConfig.toString();
} catch (Exception e) {
return;
}
}
}

View File

@ -0,0 +1,246 @@
/* Copyright (C) 2022 Arjan Schrijver
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
import android.content.Intent;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.SwitchPreference;
import android.view.MenuItem;
import java.util.LinkedHashMap;
import java.util.TimeZone;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity;
public class HybridHRWatchfaceWidgetActivity extends AbstractSettingsActivity {
private static int widgetIndex;
private static HybridHRWatchfaceWidget widget;
private static LinkedHashMap<String, String> widgetTypes;
private static String[] widgetColors;
private static final String WIDGET_2NDTZ_DEFAULT_TZ = "Etc/UTC";
private static final int WIDGET_2NDTZ_DEFAULT_TIMEOUT = 15;
private static final int WIDGET_CUSTOM_DEFAULT_TIMEOUT = 60;
private static final Boolean WIDGET_CUSTOM_DEFAULT_HIDE_TEXT = true;
private static final Boolean WIDGET_CUSTOM_DEFAULT_SHOW_CIRCLE = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
if (bundle != null) {
widgetIndex = (int) bundle.getSerializable("widgetIndex");
widget = (HybridHRWatchfaceWidget) bundle.getSerializable("widgetSettings");
} else {
throw new IllegalArgumentException("Must provide a widget object when invoking this activity");
}
getFragmentManager().beginTransaction().replace(android.R.id.content, new HybridHRWatchfaceWidgetFragment()).commit();
}
@Override
public void onBackPressed() {
// Hardware back button
Intent output = new Intent();
output.putExtra("widgetIndex", widgetIndex);
output.putExtra("widgetSettings", widget);
setResult(RESULT_OK, output);
finish();
super.onBackPressed();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
// Action bar back button
Intent output = new Intent();
output.putExtra("widgetIndex", widgetIndex);
output.putExtra("widgetSettings", widget);
setResult(RESULT_OK, output);
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
public static class HybridHRWatchfaceWidgetFragment extends PreferenceFragment implements Preference.OnPreferenceChangeListener
{
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.fossil_hr_widget_settings);
widgetTypes = HybridHRWatchfaceWidget.getAvailableWidgetTypes(getContext());
ListPreference widgetType = (ListPreference) findPreference("pref_hybridhr_widget_type");
widgetType.setOnPreferenceChangeListener(this);
widgetType.setEntries(widgetTypes.values().toArray(new String[0]));
widgetType.setEntryValues(widgetTypes.keySet().toArray(new String[0]));
widgetType.setValue(widget.getWidgetType());
widgetType.setSummary(widgetTypes.get(widget.getWidgetType()));
updateEnabledCategories();
widgetColors = new String[]{getString(R.string.watchface_dialog_widget_color_white), getString(R.string.watchface_dialog_widget_color_black)};
ListPreference widgetColor = (ListPreference) findPreference("pref_hybridhr_widget_color");
widgetColor.setOnPreferenceChangeListener(this);
widgetColor.setEntries(widgetColors);
widgetColor.setEntryValues(new String[]{"0", "1"});
widgetColor.setValueIndex(widget.getColor());
widgetColor.setSummary(widgetColors[widget.getColor()]);
EditTextPreference posX = (EditTextPreference) findPreference("pref_hybridhr_widget_pos_x");
posX.setOnPreferenceChangeListener(this);
posX.setText(Integer.toString(widget.getPosX()));
posX.setSummary(Integer.toString(widget.getPosX()));
EditTextPreference posY = (EditTextPreference) findPreference("pref_hybridhr_widget_pos_y");
posY.setOnPreferenceChangeListener(this);
posY.setText(Integer.toString(widget.getPosY()));
posY.setSummary(Integer.toString(widget.getPosY()));
LinkedHashMap<String, String> positionPresets = new LinkedHashMap<String, String>();
for (final HybridHRWidgetPosition position : widget.defaultPositions) {
positionPresets.put(String.valueOf(position.hintStringResource), getString(position.hintStringResource));
}
ListPreference widgetPositionPreset = (ListPreference) findPreference("pref_hybridhr_widget_pos_preset");
widgetPositionPreset.setOnPreferenceChangeListener(this);
widgetPositionPreset.setEntries(positionPresets.values().toArray(new String[0]));
widgetPositionPreset.setEntryValues(positionPresets.keySet().toArray(new String[0]));
String[] timezonesList = TimeZone.getAvailableIDs();
ListPreference widgetTimezone = (ListPreference) findPreference("pref_hybridhr_widget_timezone");
widgetTimezone.setOnPreferenceChangeListener(this);
widgetTimezone.setEntries(timezonesList);
widgetTimezone.setEntryValues(timezonesList);
widgetTimezone.setValue(widget.getExtraConfigString("tzName", WIDGET_2NDTZ_DEFAULT_TZ));
widgetTimezone.setSummary(widget.getExtraConfigString("tzName", WIDGET_2NDTZ_DEFAULT_TZ));
EditTextPreference timezoneDuration = (EditTextPreference) findPreference("pref_hybridhr_widget_timezone_timeout");
timezoneDuration.setOnPreferenceChangeListener(this);
timezoneDuration.setText(Integer.toString(widget.getExtraConfigInt("timeout_secs", WIDGET_2NDTZ_DEFAULT_TIMEOUT)));
timezoneDuration.setSummary(Integer.toString(widget.getExtraConfigInt("timeout_secs", WIDGET_2NDTZ_DEFAULT_TIMEOUT)));
EditTextPreference width = (EditTextPreference) findPreference("pref_hybridhr_widget_width");
width.setOnPreferenceChangeListener(this);
width.setText(Integer.toString(widget.getWidth()));
width.setSummary(Integer.toString(widget.getWidth()));
EditTextPreference customWidgetTimeout = (EditTextPreference) findPreference("pref_hybridhr_widget_custom_timeout");
customWidgetTimeout.setOnPreferenceChangeListener(this);
customWidgetTimeout.setText(Integer.toString(widget.getExtraConfigInt("update_timeout", WIDGET_CUSTOM_DEFAULT_TIMEOUT)));
customWidgetTimeout.setSummary(Integer.toString(widget.getExtraConfigInt("update_timeout", WIDGET_CUSTOM_DEFAULT_TIMEOUT)));
SwitchPreference customWidgetHideText = (SwitchPreference) findPreference("pref_hybridhr_widget_custom_hide_text");
customWidgetHideText.setOnPreferenceChangeListener(this);
customWidgetHideText.setChecked(widget.getExtraConfigBoolean("timeout_hide_text", WIDGET_CUSTOM_DEFAULT_HIDE_TEXT));
SwitchPreference customWidgetShowCircle = (SwitchPreference) findPreference("pref_hybridhr_widget_custom_show_circle");
customWidgetShowCircle.setOnPreferenceChangeListener(this);
customWidgetShowCircle.setChecked(widget.getExtraConfigBoolean("timeout_show_circle", WIDGET_CUSTOM_DEFAULT_SHOW_CIRCLE));
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
switch (preference.getKey()) {
case "pref_hybridhr_widget_type":
widget.setWidgetType(newValue.toString());
preference.setSummary(widgetTypes.get(widget.getWidgetType()));
updateEnabledCategories();
if (newValue.toString().equals("widget2ndTZ")) {
widget.setExtraConfigString("tzName", widget.getExtraConfigString("tzName", WIDGET_2NDTZ_DEFAULT_TZ));
widget.setExtraConfigInt("timeout_secs", widget.getExtraConfigInt("timeout_secs", WIDGET_2NDTZ_DEFAULT_TIMEOUT));
} else if (newValue.toString().equals("widgetCustom")) {
widget.setExtraConfigInt("update_timeout", widget.getExtraConfigInt("update_timeout", WIDGET_CUSTOM_DEFAULT_TIMEOUT));
widget.setExtraConfigBoolean("timeout_hide_text", widget.getExtraConfigBoolean("timeout_hide_text", WIDGET_CUSTOM_DEFAULT_HIDE_TEXT));
widget.setExtraConfigBoolean("timeout_show_circle", widget.getExtraConfigBoolean("timeout_show_circle", WIDGET_CUSTOM_DEFAULT_SHOW_CIRCLE));
}
break;
case "pref_hybridhr_widget_color":
widget.setColor(Integer.parseInt(newValue.toString()));
preference.setSummary(widgetColors[widget.getColor()]);
break;
case "pref_hybridhr_widget_pos_x":
widget.setPosX(Integer.parseInt(newValue.toString()));
preference.setSummary(newValue.toString());
break;
case "pref_hybridhr_widget_pos_y":
widget.setPosY(Integer.parseInt(newValue.toString()));
preference.setSummary(newValue.toString());
break;
case "pref_hybridhr_widget_pos_preset":
LinkedHashMap<String, String> positionPresets = new LinkedHashMap<String, String>();
for (final HybridHRWidgetPosition position : widget.defaultPositions){
if (newValue.toString().equals(String.valueOf(position.hintStringResource))) {
widget.setPosX(position.posX);
widget.setPosY(position.posY);
EditTextPreference prefPosX = (EditTextPreference) findPreference("pref_hybridhr_widget_pos_x");
EditTextPreference prefPosY = (EditTextPreference) findPreference("pref_hybridhr_widget_pos_y");
prefPosX.setSummary(String.valueOf(position.posX));
prefPosY.setSummary(String.valueOf(position.posY));
}
}
break;
case "pref_hybridhr_widget_timezone":
widget.setExtraConfigString("tzName", newValue.toString());
preference.setSummary(newValue.toString());
break;
case "pref_hybridhr_widget_timezone_timeout":
widget.setExtraConfigInt("timeout_secs", Integer.parseInt(newValue.toString()));
preference.setSummary(newValue.toString());
break;
case "pref_hybridhr_widget_width":
widget.setWidth(Integer.parseInt(newValue.toString()));
preference.setSummary(newValue.toString());
break;
case "pref_hybridhr_widget_custom_timeout":
widget.setExtraConfigInt("update_timeout", Integer.parseInt(newValue.toString()));
preference.setSummary(newValue.toString());
break;
case "pref_hybridhr_widget_custom_hide_text":
widget.setExtraConfigBoolean("timeout_hide_text", (boolean) newValue);
break;
case "pref_hybridhr_widget_custom_show_circle":
widget.setExtraConfigBoolean("timeout_show_circle", (boolean) newValue);
break;
}
return true;
}
private void updateEnabledCategories() {
PreferenceCategory cat2ndTZ = (PreferenceCategory) findPreference("widget_pref_category_2nd_tz_widget");
if (widget.getWidgetType().equals("widget2ndTZ")) {
cat2ndTZ.setEnabled(true);
} else {
cat2ndTZ.setEnabled(false);
}
PreferenceCategory catCustom = (PreferenceCategory) findPreference("widget_pref_category_custom_widget");
if (widget.getWidgetType().equals("widgetCustom")) {
catCustom.setEnabled(true);
} else {
catCustom.setEnabled(false);
}
}
}
}

View File

@ -0,0 +1,27 @@
/* Copyright (C) 2021 Daniel Dakhno
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
class HybridHRWidgetPosition{
int posX, posY, hintStringResource;
public HybridHRWidgetPosition(int posX, int posY, int hintStringResource) {
this.posX = posX;
this.posY = posY;
this.hintStringResource = hintStringResource;
}
}

View File

@ -1,161 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_type" />
<Spinner
android:id="@+id/watchface_widget_type_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_color" />
<Spinner
android:id="@+id/watchface_widget_color_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_x_coordinate" />
<EditText
android:id="@+id/watchface_widget_pos_x"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_y_coordinate" />
<EditText
android:id="@+id/watchface_widget_pos_y"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_presets" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/watchface_widget_preset_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_preset_top"/>
<Button
android:id="@+id/watchface_widget_preset_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_preset_bottom"/>
<Button
android:id="@+id/watchface_widget_preset_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_preset_left"/>
<Button
android:id="@+id/watchface_widget_preset_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_preset_right"/>
</LinearLayout>
<LinearLayout
android:id="@+id/watchface_widget_size_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_width" />
<EditText
android:id="@+id/watchface_widget_width"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:text="76"/>
</LinearLayout>
<LinearLayout
android:id="@+id/watchface_widget_timezone_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_timezone" />
<Spinner
android:id="@+id/watchface_widget_timezone_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/watchface_widget_timezone_timeout_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_timezone_duration" />
<EditText
android:id="@+id/watchface_widget_timezone_timeout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:text="15"/>
</LinearLayout>
<LinearLayout
android:id="@+id/watchface_widget_update_timeout_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_update_timeout" />
<EditText
android:id="@+id/watchface_widget_update_timeout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:text="60"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_timeout_hide_text" />
<CheckBox
android:id="@+id/watchface_widget_timeout_hide_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/watchface_dialog_widget_timeout_show_circle" />
<CheckBox
android:id="@+id/watchface_widget_timeout_show_circle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

View File

@ -1433,8 +1433,6 @@
<string name="button_watchface_add_widget">Add widget</string>
<string name="button_watchface_settings">Watchface settings</string>
<string name="watchface_dialog_title_set_name">Set watchface name</string>
<string name="watchface_toast_settings_incomplete">Settings incomplete, widget not added</string>
<string name="watchface_dialog_title_add_widget">Add widget</string>
<string name="watchface_widget_type_date">Date</string>
<string name="watchface_widget_type_weather">Weather</string>
<string name="watchface_widget_type_steps">Steps</string>
@ -1442,28 +1440,34 @@
<string name="button_watchface_preview">Preview on watch</string>
<string name="button_watchface_save_apply">Save and apply</string>
<string name="appmanager_app_edit">Edit</string>
<string name="watchface_dialog_widget_type">Type:</string>
<string name="watchface_dialog_widget_x_coordinate">X coordinate (max 240):</string>
<string name="watchface_dialog_widget_y_coordinate">Y coordinate (max 240):</string>
<string name="watchface_dialog_widget_presets">Position presets:</string>
<string name="watchface_dialog_widget_cat_generic">Generic</string>
<string name="watchface_dialog_widget_cat_position">Position</string>
<string name="watchface_dialog_widget_cat_2nd_tz_widget">2nd timezone widget</string>
<string name="watchface_dialog_widget_cat_custom_widget">Custom widget</string>
<string name="watchface_dialog_widget_type">Type</string>
<string name="watchface_dialog_widget_x_coordinate">X coordinate (max 240)</string>
<string name="watchface_dialog_widget_y_coordinate">Y coordinate (max 240)</string>
<string name="watchface_dialog_widget_presets">Position presets</string>
<string name="watchface_dialog_widget_preset_top">Top</string>
<string name="watchface_dialog_widget_preset_bottom">Bottom</string>
<string name="watchface_dialog_widget_preset_left">Left</string>
<string name="watchface_dialog_widget_preset_right">Right</string>
<string name="qhybrid_title_watchface_designer">Watchface designer</string>
<string name="watchface_dialog_widget_color">Color:</string>
<string name="watchface_dialog_widget_color">Color</string>
<string name="watchface_dialog_widget_color_white">White</string>
<string name="watchface_dialog_widget_color_black">Black</string>
<string name="watchface_dialog_title_settings">Watchface settings</string>
<string name="watchface_dialog_title_widget">Widget settings</string>
<string name="watchface_dialog_widget_width">Widget width (in pixels)</string>
<string name="watchface_setting_title_display_refresh_timeout">Display refresh timeout</string>
<string name="watchface_setting_display_refresh_full">Full refresh (in minutes):</string>
<string name="watchface_setting_display_refresh_partial">Partial refresh (in minutes):</string>
<string name="watchface_setting_display_refresh_full">Full refresh (in minutes)</string>
<string name="watchface_setting_display_refresh_partial">Partial refresh (in minutes)</string>
<string name="watchface_setting_title_wrist_flick">Wrist flick</string>
<string name="watchface_setting_desc_wrist_flick">(to disable completely, enable relative movement and set all values to 0)</string>
<string name="watchface_setting_wrist_flick_move_relative">Move hands relative to time:</string>
<string name="watchface_setting_wrist_flick_hour">Hour hand (-360 to 360):</string>
<string name="watchface_setting_wrist_flick_minute">Minute hand (-360 to 360):</string>
<string name="watchface_setting_wrist_flick_duration">Duration (in ms):</string>
<string name="watchface_setting_wrist_flick_move_relative">Move hands relative to time</string>
<string name="watchface_setting_wrist_flick_hour">Hour hand (-360 to 360)</string>
<string name="watchface_setting_wrist_flick_minute">Minute hand (-360 to 360)</string>
<string name="watchface_setting_wrist_flick_duration">Duration (in ms)</string>
<string name="watchface_cache_confirm_overwrite">A watchface with this name already exists in the cache. Do you want to overwrite it?</string>
<string name="watchface_upload_failed">Upload of the watchface failed. Please try again.</string>
<string name="watchface_widget_type_battery">Battery</string>
@ -1651,11 +1655,11 @@
<string name="sony_button_mode_playback_control">Playback Control</string>
<string name="sony_button_mode_volume_control">Volume Control</string>
<string name="watchface_widget_type_custom">Custom widget</string>
<string name="watchface_dialog_widget_timezone">Time zone:</string>
<string name="watchface_dialog_widget_timezone_duration">Clock visibility duration (in seconds):</string>
<string name="watchface_dialog_widget_update_timeout">Update timeout in minutes:</string>
<string name="watchface_dialog_widget_timeout_hide_text">Hide text on timeout:</string>
<string name="watchface_dialog_widget_timeout_show_circle">Show circle on timeout:</string>
<string name="watchface_dialog_widget_timezone">Time zone</string>
<string name="watchface_dialog_widget_timezone_duration">Clock visibility duration (in seconds)</string>
<string name="watchface_dialog_widget_update_timeout">Update timeout in minutes</string>
<string name="watchface_dialog_widget_timeout_hide_text">Hide text on timeout</string>
<string name="watchface_dialog_widget_timeout_show_circle">Show circle on timeout</string>
<string name="qhybrid_title_on_device_confirmation">Enable on-device pairing confirmation</string>
<string name="qhybrid_summary_on_device_confirmation">On-device pairing confirmations can get annoying. Disabling them might lose you functionality.</string>
<string name="devicetype_vesc">VESC</string>
@ -1695,7 +1699,6 @@
<string name="menuitem_menu">Menu</string>
<string name="fossil_hr_button_config_info">Some buttons cannot be configured because their functions are hard-coded in the watch firmware.\n\nWarning: long-pressing the upper button when a watchface from the official Fossil app is installed will also toggle between showing/hiding widgets.</string>
<string name="watchface_dialog_widget_width">Width:</string>
<string name="pref_title_opentracks_packagename">OpenTracks package name</string>
<string name="pref_summary_opentracks_packagename">Used for starting/stopping GPS track recording in external fitness app.</string>
<string name="watchface_dialog_pre_setting_position">pre-setting position to %s</string>

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:key="widget_pref_category_generic"
android:title="@string/watchface_dialog_widget_cat_generic">
<ListPreference
android:persistent="false"
android:title="@string/watchface_dialog_widget_type"
android:key="pref_hybridhr_widget_type"
android:dialogTitle="@string/watchface_dialog_widget_type"
android:negativeButtonText="@string/Cancel"/>
<ListPreference
android:persistent="false"
android:title="@string/watchface_dialog_widget_color"
android:key="pref_hybridhr_widget_color"
android:dialogTitle="@string/watchface_dialog_widget_color"
android:negativeButtonText="@string/Cancel"/>
</PreferenceCategory>
<PreferenceCategory
android:key="widget_pref_category_position"
android:title="@string/watchface_dialog_widget_cat_position">
<EditTextPreference
android:persistent="false"
android:key="pref_hybridhr_widget_pos_x"
android:title="@string/watchface_dialog_widget_x_coordinate"
android:inputType="numberDecimal" />
<EditTextPreference
android:persistent="false"
android:key="pref_hybridhr_widget_pos_y"
android:title="@string/watchface_dialog_widget_y_coordinate"
android:inputType="numberDecimal" />
<ListPreference
android:persistent="false"
android:title="@string/watchface_dialog_widget_presets"
android:key="pref_hybridhr_widget_pos_preset"
android:dialogTitle="@string/watchface_dialog_widget_presets"
android:negativeButtonText="@string/Cancel"/>
</PreferenceCategory>
<PreferenceCategory
android:key="widget_pref_category_2nd_tz_widget"
android:title="@string/watchface_dialog_widget_cat_2nd_tz_widget">
<ListPreference
android:persistent="false"
android:title="@string/watchface_dialog_widget_timezone"
android:key="pref_hybridhr_widget_timezone"
android:dialogTitle="@string/watchface_dialog_widget_timezone"
android:negativeButtonText="@string/Cancel"/>
<EditTextPreference
android:persistent="false"
android:key="pref_hybridhr_widget_timezone_timeout"
android:title="@string/watchface_dialog_widget_timezone_duration"
android:inputType="numberDecimal" />
</PreferenceCategory>
<PreferenceCategory
android:key="widget_pref_category_custom_widget"
android:title="@string/watchface_dialog_widget_cat_custom_widget">
<EditTextPreference
android:persistent="false"
android:key="pref_hybridhr_widget_width"
android:title="@string/watchface_dialog_widget_width"
android:inputType="numberDecimal" />
<EditTextPreference
android:persistent="false"
android:key="pref_hybridhr_widget_custom_timeout"
android:title="@string/watchface_dialog_widget_update_timeout"
android:inputType="numberDecimal" />
<SwitchPreference
android:persistent="false"
android:key="pref_hybridhr_widget_custom_hide_text"
android:title="@string/watchface_dialog_widget_timeout_hide_text"
android:singleLineTitle="false" />
<SwitchPreference
android:persistent="false"
android:key="pref_hybridhr_widget_custom_show_circle"
android:title="@string/watchface_dialog_widget_timeout_show_circle"
android:singleLineTitle="false" />
</PreferenceCategory>
</PreferenceScreen>