mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-25 11:26:47 +01:00
created UI to design custom widgets
This commit is contained in:
parent
4c86d227f1
commit
132d97ee95
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="nodomain.freeyourgadget.gadgetbridge">
|
||||
|
||||
<!--
|
||||
Comment in for testing Pebble Emulator
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
@ -22,7 +21,6 @@
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" /> <!-- Used for reverse find device -->
|
||||
|
||||
<uses-permission android:name="cyanogenmod.permission.ACCESS_WEATHER_MANAGER" />
|
||||
<uses-permission android:name="cyanogenmod.permission.READ_WEATHER" />
|
||||
<uses-permission android:name="lineageos.permission.ACCESS_WEATHER_MANAGER" />
|
||||
@ -44,16 +42,19 @@
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/GadgetbridgeTheme">
|
||||
<activity android:name=".devices.qhybrid.WidgetSettingsActivity"></activity>
|
||||
<activity
|
||||
android:name=".activities.ControlCenterv2"
|
||||
android:label="@string/title_activity_controlcenter"
|
||||
android:theme="@style/SplashTheme">
|
||||
<intent-filter>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
@ -78,9 +79,9 @@
|
||||
android:label="@string/activity_summaries"
|
||||
android:parentActivityName=".activities.ControlCenterv2" />
|
||||
<activity
|
||||
android:launchMode="singleTop"
|
||||
android:name=".activities.appmanager.AppManagerActivity"
|
||||
android:label="@string/title_activity_appmanager"
|
||||
android:launchMode="singleTop"
|
||||
android:parentActivityName=".activities.ControlCenterv2" />
|
||||
<activity
|
||||
android:name=".activities.AppBlacklistActivity"
|
||||
@ -290,7 +291,7 @@
|
||||
|
||||
<data android:mimeType="application/octet-stream" />
|
||||
</intent-filter>
|
||||
<!-- to receive firmwares from the download content provider if recognized as zip-->
|
||||
<!-- to receive firmwares from the download content provider if recognized as zip -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
@ -306,7 +307,6 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="*/*" />
|
||||
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
@ -331,18 +331,19 @@
|
||||
|
||||
<activity android:name=".externalevents.WeatherNotificationConfig">
|
||||
<intent-filter>
|
||||
<action android:name="ru.gelin.android.weather.notification.ACTION_WEATHER_SKIN_PREFERENCES"/>
|
||||
<action android:name="ru.gelin.android.weather.notification.ACTION_WEATHER_SKIN_PREFERENCES" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver android:name=".externalevents.AutoStartReceiver"
|
||||
<receiver
|
||||
android:name=".externalevents.AutoStartReceiver"
|
||||
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".externalevents.BluetoothStateChangeReceiver"
|
||||
android:exported="false">
|
||||
@ -365,16 +366,13 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".database.PeriodicExporter"
|
||||
android:enabled="true"
|
||||
android:name="nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter"
|
||||
android:exported="false">
|
||||
|
||||
</receiver>
|
||||
|
||||
android:exported="false"></receiver>
|
||||
<!--
|
||||
forcing the DebugActivity to portrait mode avoids crashes with the progress
|
||||
dialog when changing orientation
|
||||
-->
|
||||
-->
|
||||
<activity
|
||||
android:name=".activities.DebugActivity"
|
||||
android:label="@string/title_activity_debug"
|
||||
@ -402,10 +400,10 @@
|
||||
android:label="@string/title_activity_pebble_pairing" />
|
||||
<activity
|
||||
android:name=".devices.watch9.Watch9PairingActivity"
|
||||
android:label="@string/title_activity_watch9_pairing" />
|
||||
android:label="@string/title_activity_watch9_pairing" />
|
||||
<activity
|
||||
android:name=".devices.watch9.Watch9CalibrationActivity"
|
||||
android:label="@string/title_activity_watch9_calibration" />
|
||||
android:label="@string/title_activity_watch9_calibration" />
|
||||
<activity
|
||||
android:name=".activities.charts.ChartsActivity"
|
||||
android:label="@string/title_activity_charts"
|
||||
@ -429,8 +427,8 @@
|
||||
<activity
|
||||
android:name=".activities.NotificationFilterActivity"
|
||||
android:label="@string/title_activity_notification_filter"
|
||||
android:windowSoftInputMode="stateHidden|adjustPan"
|
||||
android:parentActivityName=".activities.AppBlacklistActivity" />
|
||||
android:parentActivityName=".activities.AppBlacklistActivity"
|
||||
android:windowSoftInputMode="stateHidden|adjustPan" />
|
||||
<activity
|
||||
android:name=".activities.FindPhoneActivity"
|
||||
android:label="Find Phone" />
|
||||
@ -439,7 +437,6 @@
|
||||
android:name=".contentprovider.PebbleContentProvider"
|
||||
android:authorities="com.getpebble.android.provider"
|
||||
android:exported="true" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.screenshot_provider"
|
||||
@ -450,7 +447,8 @@
|
||||
android:resource="@xml/shared_paths" />
|
||||
</provider>
|
||||
|
||||
<receiver android:name=".SleepAlarmWidget"
|
||||
<receiver
|
||||
android:name=".SleepAlarmWidget"
|
||||
android:label="@string/appwidget_sleep_alarm_widget_label">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
@ -461,41 +459,41 @@
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/sleep_alarm_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".Widget"
|
||||
android:label="@string/widget_listing_label">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
<action android:name="nodomain.freeyourgadget.gadgetbridge.WidgetClick" />
|
||||
</intent-filter>
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_info" />
|
||||
</receiver>
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".activities.WidgetAlarmsActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:theme="@style/Theme.AppCompat.Light.Dialog"
|
||||
android:excludeFromRecents="true"/>
|
||||
|
||||
android:theme="@style/Theme.AppCompat.Light.Dialog" />
|
||||
<activity
|
||||
android:launchMode="singleTask"
|
||||
android:name=".activities.ExternalPebbleJSActivity"
|
||||
android:allowTaskReparenting="true"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:name=".activities.ExternalPebbleJSActivity"
|
||||
android:label="@string/app_configure"
|
||||
android:launchMode="singleTask"
|
||||
android:parentActivityName=".activities.appmanager.AppManagerActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="gadgetbridge" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
@ -1,15 +1,11 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.TextureView;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
@ -25,21 +21,33 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.w3c.dom.Text;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomBackgroundWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomTextWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.Widget;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.WidgetSettingsActivity.RESULT_CODE_WIDGET_DELETED;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.QHYBRID_COMMAND_UPDATE_WIDGETS;
|
||||
|
||||
public class HRConfigActivity extends AbstractGBActivity implements View.OnClickListener, DialogInterface.OnClickListener, AdapterView.OnItemClickListener {
|
||||
private SharedPreferences sharedPreferences;
|
||||
private ActionListAdapter actionListAdapter;
|
||||
private WidgetListAdapter widgetListAdapter;
|
||||
private ArrayList<MenuAction> menuActions = new ArrayList<>();
|
||||
private ArrayList<CustomWidget> customWidgets = new ArrayList<>();
|
||||
|
||||
SparseArray<String> widgetButtonsMapping = new SparseArray<>(4);
|
||||
|
||||
static public final String CONFIG_KEY_Q_ACTIONS = "Q_ACTIONS";
|
||||
|
||||
@ -52,14 +60,266 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
|
||||
|
||||
sharedPreferences = GBApplication.getPrefs().getPreferences();
|
||||
|
||||
initMappings();
|
||||
loadWidgetConfigs();
|
||||
|
||||
|
||||
ListView actionListView = findViewById(R.id.qhybrid_action_list);
|
||||
actionListAdapter = new ActionListAdapter(menuActions);
|
||||
actionListView.setAdapter(actionListAdapter);
|
||||
actionListView.setOnItemClickListener(this);
|
||||
|
||||
final ListView widgetListView = findViewById(R.id.qhybrid_widget_list);
|
||||
widgetListAdapter = new WidgetListAdapter(customWidgets);
|
||||
widgetListView.setAdapter(widgetListAdapter);
|
||||
widgetListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
Widget widget = widgetListAdapter.getItem(position);
|
||||
|
||||
Intent startIntent = new Intent(HRConfigActivity.this, WidgetSettingsActivity.class);
|
||||
startIntent.putExtra("EXTRA_WIDGET", widget);
|
||||
startIntent.putExtra("EXTRA_WIDGET_IDNEX", position);
|
||||
|
||||
startActivityForResult(startIntent, 0);
|
||||
}
|
||||
});
|
||||
loadCustomWidgetList();
|
||||
|
||||
findViewById(R.id.qhybrid_widget_add).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent startIntent = new Intent(HRConfigActivity.this, WidgetSettingsActivity.class);
|
||||
|
||||
startActivityForResult(startIntent, 0);
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < widgetButtonsMapping.size(); i++) {
|
||||
final int widgetButtonId = widgetButtonsMapping.keyAt(i);
|
||||
findViewById(widgetButtonId).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Widget.WidgetType[] types = Widget.WidgetType.values();
|
||||
final ArrayList<String> names = new ArrayList<>(types.length);
|
||||
|
||||
for (Widget.WidgetType type : types) {
|
||||
names.add(getResources().getString(type.getStringResource()));
|
||||
}
|
||||
|
||||
for(CustomWidget customWidget : customWidgets){
|
||||
names.add(customWidget.getName());
|
||||
}
|
||||
|
||||
final String[] nameStrings = names.toArray(new String[0]);
|
||||
new AlertDialog.Builder(HRConfigActivity.this)
|
||||
.setItems(
|
||||
nameStrings,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
saveWidgetSetting(widgetButtonId, which, nameStrings);
|
||||
}
|
||||
}
|
||||
)
|
||||
.show();
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if(data == null) return;
|
||||
if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_CREATED) {
|
||||
CustomWidget widget = (CustomWidget) data.getExtras().get("EXTRA_WIDGET");
|
||||
this.customWidgets.add(widget);
|
||||
refreshWidgetList();
|
||||
saveCustomWidgetList();
|
||||
|
||||
LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
|
||||
} else if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_UPDATED) {
|
||||
CustomWidget widget = (CustomWidget) data.getExtras().get("EXTRA_WIDGET");
|
||||
int updateIndex = data.getIntExtra("EXTRA_WIDGET_IDNEX", -1);
|
||||
|
||||
this.customWidgets.set(updateIndex, widget);
|
||||
|
||||
refreshWidgetList();
|
||||
saveCustomWidgetList();
|
||||
|
||||
LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
|
||||
} else if (resultCode == WidgetSettingsActivity.RESULT_CODE_WIDGET_DELETED){
|
||||
int updateIndex = data.getIntExtra("EXTRA_WIDGET_IDNEX", -1);
|
||||
|
||||
this.customWidgets.remove(updateIndex);
|
||||
|
||||
refreshWidgetList();
|
||||
saveCustomWidgetList();
|
||||
|
||||
LocalBroadcastManager.getInstance(HRConfigActivity.this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void saveCustomWidgetList() {
|
||||
try {
|
||||
JSONArray widgetArray = new JSONArray();
|
||||
for(CustomWidget widget : customWidgets){
|
||||
JSONArray elementArray = new JSONArray();
|
||||
|
||||
for(CustomWidgetElement element : widget.getElements()){
|
||||
JSONObject elementObject = new JSONObject();
|
||||
elementObject
|
||||
.put("type", element.getWidgetElementType().getJsonIdentifier())
|
||||
.put("id", element.getId())
|
||||
.put("value", element.getValue())
|
||||
.put("x", element.getX())
|
||||
.put("y", element.getY());
|
||||
elementArray.put(elementObject);
|
||||
}
|
||||
|
||||
JSONObject widgetObject = new JSONObject();
|
||||
widgetObject
|
||||
.put("name", widget.getName())
|
||||
.put("elements", elementArray);
|
||||
|
||||
widgetArray.put(widgetObject);
|
||||
}
|
||||
sharedPreferences.edit().putString("QHYBRID_CUSTOM_WIDGETS", widgetArray.toString()).apply();
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadCustomWidgetList() {
|
||||
String customWidgetJson = sharedPreferences.getString("QHYBRID_CUSTOM_WIDGETS", "[]");
|
||||
|
||||
try {
|
||||
JSONArray customWidgets = new JSONArray(customWidgetJson);
|
||||
this.customWidgets.clear();
|
||||
|
||||
for (int i = 0; i < customWidgets.length(); i++) {
|
||||
JSONObject customWidgetObject = customWidgets.getJSONObject(i);
|
||||
CustomWidget widget = new CustomWidget(
|
||||
customWidgetObject.getString("name"), 0, 0
|
||||
);
|
||||
JSONArray elements = customWidgetObject.getJSONArray("elements");
|
||||
|
||||
for (int i2 = 0; i2 < elements.length(); i2++) {
|
||||
JSONObject element = elements.getJSONObject(i2);
|
||||
if (element.getString("type").equals("text")) {
|
||||
widget.addElement(new CustomTextWidgetElement(
|
||||
element.getString("id"),
|
||||
element.getString("value"),
|
||||
element.getInt("x"),
|
||||
element.getInt("y")
|
||||
));
|
||||
} else if (element.getString("type").equals("background")) {
|
||||
widget.addElement(new CustomBackgroundWidgetElement(
|
||||
element.getString("id"),
|
||||
element.getString("value")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
this.customWidgets.add(widget);
|
||||
}
|
||||
|
||||
refreshWidgetList();
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshWidgetList() {
|
||||
widgetListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void saveWidgetSetting(int buttonId, int option, String[] names) {
|
||||
String jsonKey = widgetButtonsMapping.get(buttonId);
|
||||
Widget.WidgetType[] types = Widget.WidgetType.values();
|
||||
String identifier = null;
|
||||
if(option < types.length){
|
||||
Widget.WidgetType type = types[option];
|
||||
identifier = type.getIdentifier();
|
||||
}else{
|
||||
identifier = "custom_" + names[option];
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject keyConfig = new JSONObject(sharedPreferences.getString("FOSSIL_HR_WIDGETS", "{}"));
|
||||
if (identifier != null) {
|
||||
keyConfig.put(jsonKey, identifier);
|
||||
} else {
|
||||
keyConfig.remove(jsonKey);
|
||||
}
|
||||
sharedPreferences.edit().putString("FOSSIL_HR_WIDGETS", keyConfig.toString()).apply();
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(QHYBRID_COMMAND_UPDATE_WIDGETS));
|
||||
|
||||
loadWidgetConfigs();
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void loadWidgetConfigs() {
|
||||
try {
|
||||
for (int i = 0; i < widgetButtonsMapping.size(); i++) {
|
||||
((TextView) findViewById(widgetButtonsMapping.keyAt(i))).setText(widgetButtonsMapping.valueAt(i) + " widget");
|
||||
}
|
||||
|
||||
JSONObject keyConfig = new JSONObject(sharedPreferences.getString("FOSSIL_HR_WIDGETS", "{}"));
|
||||
Iterator<String> keyIterator = keyConfig.keys();
|
||||
|
||||
loop:
|
||||
while (keyIterator.hasNext()) {
|
||||
String position = keyIterator.next();
|
||||
|
||||
for (int widgetButtonIndex = 0; widgetButtonIndex < widgetButtonsMapping.size(); widgetButtonIndex++) {
|
||||
if (position.equals(widgetButtonsMapping.valueAt(widgetButtonIndex))) {
|
||||
int buttonId = widgetButtonsMapping.keyAt(widgetButtonIndex);
|
||||
String function = keyConfig.getString(position);
|
||||
|
||||
Widget.WidgetType[] types = Widget.WidgetType.values();
|
||||
if(function.startsWith("custom_")){
|
||||
((TextView) findViewById(buttonId)).setText(
|
||||
position + " widget: " + function.substring(7)
|
||||
);
|
||||
continue loop;
|
||||
}
|
||||
for (int widgetIdIndex = 0; widgetIdIndex < types.length; widgetIdIndex++) {
|
||||
String widgetIdMappingValue = types[widgetIdIndex].getIdentifier();
|
||||
if (widgetIdMappingValue != null && widgetIdMappingValue.equals(function)) {
|
||||
((TextView) findViewById(buttonId)).setText(
|
||||
position + " widget: "
|
||||
+ getResources().getText(
|
||||
types[widgetIdIndex].getStringResource()
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void initMappings() {
|
||||
widgetButtonsMapping.put(R.id.qhybrid_button_widget_top, "top");
|
||||
widgetButtonsMapping.put(R.id.qhybrid_button_widget_right, "right");
|
||||
widgetButtonsMapping.put(R.id.qhybrid_button_widget_bottom, "bottom");
|
||||
widgetButtonsMapping.put(R.id.qhybrid_button_widget_left, "left");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v.getId() == R.id.qhybrid_action_add) {
|
||||
@ -147,7 +407,7 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
|
||||
.show();
|
||||
}
|
||||
|
||||
private void putActionItems(List<MenuAction> actions){
|
||||
private void putActionItems(List<MenuAction> actions) {
|
||||
JSONArray array = new JSONArray();
|
||||
for (MenuAction action : actions) array.put(action.getAction());
|
||||
|
||||
@ -170,6 +430,25 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
|
||||
}
|
||||
}
|
||||
|
||||
class WidgetListAdapter extends ArrayAdapter<CustomWidget> {
|
||||
public WidgetListAdapter(@NonNull List<CustomWidget> objects) {
|
||||
super(HRConfigActivity.this, 0, objects);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
if (convertView == null) convertView = new TextView(getContext());
|
||||
TextView view = (TextView) convertView;
|
||||
|
||||
view.setText(getItem(position).getName());
|
||||
// view.setTextColor(Color.WHITE);
|
||||
view.setTextSize(25);
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
class ActionListAdapter extends ArrayAdapter<MenuAction> {
|
||||
public ActionListAdapter(@NonNull ArrayList<MenuAction> objects) {
|
||||
super(HRConfigActivity.this, 0, objects);
|
||||
@ -183,7 +462,7 @@ public class HRConfigActivity extends AbstractGBActivity implements View.OnClick
|
||||
|
||||
view.setText(getItem(position).getAction());
|
||||
// view.setTextColor(Color.WHITE);
|
||||
view.setTextSize(30);
|
||||
view.setTextSize(25);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
@ -0,0 +1,208 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.Widget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomBackgroundWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomTextWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidgetElement;
|
||||
|
||||
public class WidgetSettingsActivity extends AbstractGBActivity {
|
||||
private CustomWidget subject;
|
||||
private WidgetElementAdapter widgetElementAdapter;
|
||||
|
||||
public static final int RESULT_CODE_WIDGET_CREATED = 0;
|
||||
public static final int RESULT_CODE_WIDGET_UPDATED = 1;
|
||||
public static final int RESULT_CODE_WIDGET_DELETED = 2;
|
||||
public static final int RESULT_CODE_CANCELED = 3;
|
||||
|
||||
private int resultCode;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.qhybrid_activity_widget_settings);
|
||||
|
||||
setResult(RESULT_CODE_CANCELED);
|
||||
|
||||
if(getIntent().hasExtra("EXTRA_WIDGET")){
|
||||
subject = (CustomWidget) getIntent().getExtras().get("EXTRA_WIDGET");
|
||||
((EditText) findViewById(R.id.qhybrid_widget_name)).setText(subject.getName());
|
||||
resultCode = RESULT_CODE_WIDGET_UPDATED;
|
||||
}else{
|
||||
subject = new CustomWidget("", 0, 63);
|
||||
resultCode = RESULT_CODE_WIDGET_CREATED;
|
||||
findViewById(R.id.qhybrid_widget_delete).setEnabled(false);
|
||||
}
|
||||
|
||||
findViewById(R.id.qhybrid_widget_save).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
subject.setName(((EditText) findViewById(R.id.qhybrid_widget_name)).getText().toString());
|
||||
|
||||
Intent resultIntent = getIntent();
|
||||
resultIntent.putExtra("EXTRA_WIDGET", WidgetSettingsActivity.this.subject);
|
||||
setResult(resultCode, resultIntent);
|
||||
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.qhybrid_widget_delete).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setResult(RESULT_CODE_WIDGET_DELETED, getIntent());
|
||||
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
widgetElementAdapter = new WidgetElementAdapter(subject.getElements());
|
||||
ListView elementList = findViewById(R.id.qhybrid_widget_elements_list);
|
||||
elementList.setAdapter(widgetElementAdapter);
|
||||
elementList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
showElementDialog(widgetElementAdapter.getItem(position));
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.qhybrid_widget_elements_add).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showElementDialog(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showElementDialog(@Nullable final CustomWidgetElement element){
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(WidgetSettingsActivity.this)
|
||||
.setView(R.layout.qhybrid_element_popup_view);
|
||||
|
||||
if(element == null) {
|
||||
dialogBuilder
|
||||
.setTitle("create element")
|
||||
.setNegativeButton("cancel", null)
|
||||
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if(((RadioButton)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_elements_type_text)).isChecked()){
|
||||
subject.addElement(new CustomTextWidgetElement(
|
||||
((EditText)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_element_id)).getText().toString(),
|
||||
((EditText)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_element_value)).getText().toString(),
|
||||
CustomWidgetElement.X_CENTER,
|
||||
((RadioButton)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_elements_position_uppper)).isChecked() ? CustomTextWidgetElement.Y_UPPER_HALF : CustomTextWidgetElement.Y_LOWER_HALF
|
||||
));
|
||||
}else{
|
||||
subject.addElement(new CustomBackgroundWidgetElement(
|
||||
((EditText)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_element_id)).getText().toString(),
|
||||
((EditText)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_element_value)).getText().toString()
|
||||
));
|
||||
}
|
||||
refreshElementsList();
|
||||
}
|
||||
});
|
||||
}else{
|
||||
dialogBuilder
|
||||
.setTitle("edit element")
|
||||
.setNegativeButton("delete", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
WidgetSettingsActivity.this.subject.getElements().remove(element);
|
||||
|
||||
refreshElementsList();
|
||||
}
|
||||
})
|
||||
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
element.setId(((EditText)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_element_id)).getText().toString());
|
||||
element.setValue(((EditText)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_element_value)).getText().toString());
|
||||
element.setY(((RadioButton)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_elements_position_uppper)).isChecked() ? CustomTextWidgetElement.Y_UPPER_HALF : CustomTextWidgetElement.Y_LOWER_HALF);
|
||||
element.setWidgetElementType(CustomWidgetElement.WidgetElementType.fromRadioButtonRessource(((RadioGroup)((AlertDialog)dialog).findViewById(R.id.qhybrid_widget_element_type)).getCheckedRadioButtonId()));
|
||||
|
||||
refreshElementsList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
AlertDialog dialog = dialogBuilder.show();
|
||||
|
||||
|
||||
if(element != null){
|
||||
String elementId = element.getId();
|
||||
String elementValue = element.getValue();
|
||||
CustomWidgetElement.WidgetElementType type = element.getWidgetElementType();
|
||||
|
||||
((EditText)dialog.findViewById(R.id.qhybrid_widget_element_id)).setText(elementId);
|
||||
((EditText)dialog.findViewById(R.id.qhybrid_widget_element_value)).setText(elementValue);
|
||||
((RadioGroup)dialog.findViewById(R.id.qhybrid_widget_element_type)).check(type.getRadioButtonResource());
|
||||
((RadioGroup)dialog.findViewById(R.id.qhybrid_widget_element_position)).check(element.getY() == CustomWidgetElement.Y_UPPER_HALF ? R.id.qhybrid_widget_elements_position_uppper : R.id.qhybrid_widget_elements_position_lower);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshElementsList(){
|
||||
this.widgetElementAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
class WidgetElementAdapter extends ArrayAdapter<CustomWidgetElement>{
|
||||
public WidgetElementAdapter(@NonNull List<CustomWidgetElement> objects) {
|
||||
super(WidgetSettingsActivity.this, 0, objects);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
RelativeLayout layout = new RelativeLayout(WidgetSettingsActivity.this);
|
||||
layout.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
|
||||
TextView idView = new TextView(WidgetSettingsActivity.this);
|
||||
|
||||
idView.setText(getItem(position).getId());
|
||||
// view.setTextColor(Color.WHITE);
|
||||
idView.setTextSize(25);
|
||||
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.addRule(RelativeLayout.ALIGN_PARENT_START, RelativeLayout.TRUE);
|
||||
idView.setLayoutParams(params);
|
||||
|
||||
TextView contentView = new TextView(WidgetSettingsActivity.this);
|
||||
contentView.setText(getItem(position).getValue());
|
||||
contentView.setTextSize(25);
|
||||
params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.addRule(RelativeLayout.ALIGN_PARENT_END, RelativeLayout.TRUE);
|
||||
contentView.setLayoutParams(params);
|
||||
|
||||
layout.addView(idView);
|
||||
layout.addView(contentView);
|
||||
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
}
|
@ -87,6 +87,7 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
public static final String QHYBRID_COMMAND_NOTIFICATION = "qhybrid_command_notification";
|
||||
public static final String QHYBRID_COMMAND_UPDATE_SETTINGS = "nodomain.freeyourgadget.gadgetbridge.Q_UPDATE_SETTINGS";
|
||||
public static final String QHYBRID_COMMAND_OVERWRITE_BUTTONS = "nodomain.freeyourgadget.gadgetbridge.Q_OVERWRITE_BUTTONS";
|
||||
public static final String QHYBRID_COMMAND_UPDATE_WIDGETS = "nodomain.freeyourgadget.gadgetbridge.Q_UPDATE_WIDGETS";
|
||||
public static final String QHYBRID_COMMAND_SET_MENU_MESSAGE = "nodomain.freeyourgadget.gadgetbridge.Q_SET_MENU_MESSAGE";
|
||||
public static final String QHYBRID_COMMAND_SEND_MENU_ITEMS = "nodomain.freeyourgadget.gadgetbridge.Q_SEND_MENU_ITEMS";
|
||||
public static final String QHYBRID_COMMAND_SET_WIDGET_CONTENT = "nodomain.freeyourgadget.gadgetbridge.Q_SET_WIDGET_CONTENT";
|
||||
@ -143,6 +144,7 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
commandFilter.addAction(QHYBRID_COMMAND_UPDATE_SETTINGS);
|
||||
commandFilter.addAction(QHYBRID_COMMAND_OVERWRITE_BUTTONS);
|
||||
commandFilter.addAction(QHYBRID_COMMAND_NOTIFICATION_CONFIG_CHANGED);
|
||||
commandFilter.addAction(QHYBRID_COMMAND_UPDATE_WIDGETS);
|
||||
commandFilter.addAction(QHYBRID_COMMAND_SEND_MENU_ITEMS);
|
||||
commandReceiver = new BroadcastReceiver() {
|
||||
|
||||
@ -217,6 +219,10 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
watchAdapter.syncNotificationSettings();
|
||||
break;
|
||||
}
|
||||
case QHYBRID_COMMAND_UPDATE_WIDGETS: {
|
||||
watchAdapter.updateWidgets();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -278,6 +284,7 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
widgetValues.put(key.substring(16), String.valueOf(intent.getExtras().get(key)));
|
||||
}
|
||||
}
|
||||
boolean render = intent.getBooleanExtra("EXTRA_RENDER", true);
|
||||
if(widgetValues.size() > 0){
|
||||
Iterator<String> valuesIterator = widgetValues.keySet().iterator();
|
||||
valuesIterator.next();
|
||||
@ -289,11 +296,10 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
|
||||
valuesIterator = widgetValues.keySet().iterator();
|
||||
String id = valuesIterator.next();
|
||||
watchAdapter.setWidgetContent(id, widgetValues.get(id), true);
|
||||
watchAdapter.setWidgetContent(id, widgetValues.get(id), render);
|
||||
}else {
|
||||
String id = String.valueOf(intent.getExtras().get("EXTRA_WIDGET_ID"));
|
||||
String content = String.valueOf(intent.getExtras().get("EXTRA_CONTENT"));
|
||||
boolean render = intent.getBooleanExtra("EXTRA_RENDER", true);
|
||||
watchAdapter.setWidgetContent(id, content, render);
|
||||
}
|
||||
break;
|
||||
@ -352,7 +358,7 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
.read(getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb")))
|
||||
.read(getCharacteristic(UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb")))
|
||||
.read(getCharacteristic(UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb")))
|
||||
.notify(getCharacteristic(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb")), true)
|
||||
// .notify(getCharacteristic(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb")), true)
|
||||
;
|
||||
|
||||
|
||||
@ -474,6 +480,12 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
return notificationProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
||||
super.onConnectionStateChange(gatt, status, newState);
|
||||
watchAdapter.onConnectionStateChange(gatt, status, newState);
|
||||
}
|
||||
|
||||
//TODO toggle "Notifications when screen on" options on this check
|
||||
private void showNotificationCountOnActivityHand(double progress) {
|
||||
if (useActivityHand) {
|
||||
@ -612,6 +624,12 @@ public class QHybridSupport extends QHybridBaseSupport {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
||||
watchAdapter.onCharacteristicWrite(gatt, characteristic, status);
|
||||
return super.onCharacteristicWrite(gatt, characteristic, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
||||
switch (characteristic.getUuid().toString()) {
|
||||
|
@ -108,4 +108,13 @@ public abstract class WatchAdapter {
|
||||
|
||||
public void setWidgetContent(String widgetID, String content, boolean render) {
|
||||
}
|
||||
|
||||
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
||||
}
|
||||
|
||||
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
||||
}
|
||||
|
||||
public void updateWidgets() {
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.PackageConfigHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BTLEOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.WatchAdapter;
|
||||
@ -130,6 +131,25 @@ public class FossilWatchAdapter extends WatchAdapter {
|
||||
overwriteButtons(buttonConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
||||
if(status != BluetoothGatt.GATT_SUCCESS){
|
||||
log("characteristic write failed: " + status);
|
||||
fossilRequest = null;
|
||||
|
||||
queueNextRequest();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
||||
if(newState != BluetoothGatt.STATE_CONNECTED){
|
||||
log("status " + newState + " clearing queue...");
|
||||
requestQueue.clear();
|
||||
fossilRequest = null;
|
||||
}
|
||||
}
|
||||
|
||||
private SharedPreferences getDeviceSpecificPreferences(){
|
||||
return GBApplication.getDeviceSpecificSharedPrefs(
|
||||
getDeviceSupport().getDevice().getAddress()
|
||||
|
@ -9,47 +9,39 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Build;
|
||||
import android.os.CpuUsageInfo;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Random;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
|
||||
import cyanogenmod.app.CustomTile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.Widget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HRConfigActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationConfiguration;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.RequestMtuRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.SetDeviceStateRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.configuration.ConfigurationPutRequest.TimeConfigItem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FileCloseRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FileDeleteRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayNotificationRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.VerifyPrivateKeyRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.buttons.ButtonConfigurationPutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.configuration.ConfigurationGetRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.configuration.ConfigurationPutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.AssetFile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.AssetFilePutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.AssetImage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.AssetImageFactory;
|
||||
@ -58,14 +50,12 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicControlRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicInfoSetRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.NotificationFilterPutHRRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.NotificationImage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.NotificationImagePutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.PlayNotificationHRRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomBackgroundWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomTextWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidgetElement;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.utils.StringUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.Widget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.WidgetsPutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicControlRequest.MUSIC_PHONE_REQUEST;
|
||||
@ -75,7 +65,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
private byte[] phoneRandomNumber;
|
||||
private byte[] watchRandomNumber;
|
||||
|
||||
CustomWidget[] widgets = new CustomWidget[0];
|
||||
ArrayList<Widget> widgets = new ArrayList<>();
|
||||
|
||||
NotificationHRConfiguration[] notificationConfigurations;
|
||||
|
||||
@ -176,37 +166,87 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
.decodeFile("/sdcard/DCIM/Camera/IMG_20191129_200726.jpg");
|
||||
|
||||
try {
|
||||
this.backGroundImage = AssetImageFactory.createAssetImage(backgroundBitmap, false, 0, 0, 0);
|
||||
this.backGroundImage = AssetImageFactory.createAssetImage(backgroundBitmap, false, 0,:wq
|
||||
0, 0);
|
||||
} catch (IOException e) {
|
||||
GB.log("Backgroundimage error", GB.ERROR, e);
|
||||
}*/
|
||||
}
|
||||
|
||||
private void loadWidgets() {
|
||||
CustomWidget ethWidget = new CustomWidget(90, 63);
|
||||
// ethWidget.addElement(new CustomWidgetElement(CustomWidgetElement.WidgetElementType.TYPE_TEXT, "date", "-", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_UPPER_HALF));
|
||||
ethWidget.addElement(new CustomTextWidgetElement("ETH", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_UPPER_HALF));
|
||||
ethWidget.addElement(new CustomTextWidgetElement("eth", "-", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_LOWER_HALF));
|
||||
this.widgets.clear();
|
||||
String widgetJson = GBApplication.getPrefs().getPreferences().getString("FOSSIL_HR_WIDGETS", "{}");
|
||||
String customWidgetJson = GBApplication.getPrefs().getString("QHYBRID_CUSTOM_WIDGETS", "[]");
|
||||
|
||||
try {
|
||||
JSONObject widgetConfig = new JSONObject(widgetJson);
|
||||
JSONArray customWidgets = new JSONArray(customWidgetJson);
|
||||
|
||||
CustomWidget btcWidget = new CustomWidget(270, 63);
|
||||
btcWidget.addElement(new CustomTextWidgetElement("BTC", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_UPPER_HALF));
|
||||
btcWidget.addElement(new CustomTextWidgetElement("btc", "-", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_LOWER_HALF));
|
||||
Iterator<String> keyIterator = widgetConfig.keys();
|
||||
HashMap<String, Integer> positionMap = new HashMap<>(4);
|
||||
positionMap.put("top", 0);
|
||||
positionMap.put("right", 90);
|
||||
positionMap.put("bottom", 180);
|
||||
positionMap.put("left", 270);
|
||||
|
||||
CustomWidget dateWidget = new CustomWidget(0, 63);
|
||||
dateWidget.addElement(new CustomTextWidgetElement("Time", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_UPPER_HALF));
|
||||
dateWidget.addElement(new CustomTextWidgetElement("date", "-", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_LOWER_HALF));
|
||||
while(keyIterator.hasNext()){
|
||||
String position = keyIterator.next();
|
||||
String identifier = widgetConfig.getString(position);
|
||||
Widget.WidgetType type = Widget.WidgetType.fromJsonIdentifier(identifier);
|
||||
|
||||
CustomWidget helloWidget = new CustomWidget(180, 63);
|
||||
// helloWidget.addElement(new CustomTextWidgetElement("Hello", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_UPPER_HALF));
|
||||
// helloWidget.addElement(new CustomTextWidgetElement("Reddit", CustomWidgetElement.X_CENTER, CustomWidgetElement.Y_LOWER_HALF));
|
||||
helloWidget.addElement(new CustomBackgroundWidgetElement("reddit", "/sdcard/reddit.png"));
|
||||
this.widgets = new CustomWidget[]{
|
||||
ethWidget,
|
||||
btcWidget,
|
||||
dateWidget,
|
||||
helloWidget
|
||||
};
|
||||
Widget widget = null;
|
||||
if(type != null) {
|
||||
widget = new Widget(type, positionMap.get(position), 63);
|
||||
}else{
|
||||
identifier = identifier.substring(7);
|
||||
for(int i = 0; i < customWidgets.length(); i++){
|
||||
JSONObject customWidget = customWidgets.getJSONObject(i);
|
||||
if(customWidget.getString("name").equals(identifier)){
|
||||
CustomWidget newWidget = new CustomWidget(
|
||||
customWidget.getString("name"),
|
||||
positionMap.get(position),
|
||||
63
|
||||
);
|
||||
JSONArray elements = customWidget.getJSONArray("elements");
|
||||
|
||||
for (int i2 = 0; i2 < elements.length(); i2++) {
|
||||
JSONObject element = elements.getJSONObject(i2);
|
||||
if (element.getString("type").equals("text")) {
|
||||
newWidget.addElement(new CustomTextWidgetElement(
|
||||
element.getString("id"),
|
||||
element.getString("value"),
|
||||
element.getInt("x"),
|
||||
element.getInt("y")
|
||||
));
|
||||
} else if (element.getString("type").equals("background")) {
|
||||
newWidget.addElement(new CustomBackgroundWidgetElement(
|
||||
element.getString("id"),
|
||||
element.getString("value")
|
||||
));
|
||||
}
|
||||
}
|
||||
widget = newWidget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(widget == null) continue;
|
||||
this.widgets.add(widget);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
uploadWidgets();
|
||||
}
|
||||
|
||||
private void uploadWidgets(){
|
||||
negotiateSymmetricKey();
|
||||
ArrayList<Widget> systemWidgets = new ArrayList<>(widgets.size());
|
||||
for(Widget widget : this.widgets){
|
||||
if(!(widget instanceof CustomWidget)) systemWidgets.add(widget);
|
||||
}
|
||||
queueWrite(new WidgetsPutRequest(systemWidgets.toArray(new Widget[0]), this));
|
||||
}
|
||||
|
||||
private void renderWidgets() {
|
||||
@ -218,8 +258,10 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < this.widgets.length; i++) {
|
||||
CustomWidget widget = widgets[i];
|
||||
for (int i = 0; i < this.widgets.size(); i++) {
|
||||
Widget w = widgets.get(i);
|
||||
if(!(w instanceof CustomWidget)) continue;
|
||||
CustomWidget widget = (CustomWidget) w;
|
||||
|
||||
Bitmap widgetBitmap = Bitmap.createBitmap(76, 76, Bitmap.Config.ARGB_8888);
|
||||
|
||||
@ -312,8 +354,9 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
@Override
|
||||
public void setWidgetContent(String widgetID, String content, boolean renderOnWatch) {
|
||||
boolean update = false;
|
||||
for (CustomWidget widget : this.widgets) {
|
||||
if(widget.updateElementValue(widgetID, content)) update = true;
|
||||
for (Widget widget : this.widgets) {
|
||||
if(!(widget instanceof CustomWidget)) continue;
|
||||
if(((CustomWidget) widget).updateElementValue(widgetID, content)) update = true;
|
||||
}
|
||||
|
||||
if (renderOnWatch && update) renderWidgets();
|
||||
@ -374,6 +417,12 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWidgets() {
|
||||
loadWidgets();
|
||||
renderWidgets();
|
||||
}
|
||||
|
||||
private void setBackgroundImages(AssetImage background, AssetImage[] complications) {
|
||||
queueWrite(new ImagesSetRequest(new AssetImage[]{background}, this));
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSuppo
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.configuration.ConfigurationPutRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.FileEncryptedLookupAndGetRequest;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class ConfigurationGetRequest extends FileEncryptedLookupAndGetRequest {
|
||||
public ConfigurationGetRequest(FossilHRWatchAdapter adapter) {
|
||||
@ -49,6 +50,8 @@ public class ConfigurationGetRequest extends FileEncryptedLookupAndGetRequest {
|
||||
}
|
||||
}
|
||||
|
||||
GB.toast("got config", 0, GB.INFO);
|
||||
|
||||
device.sendDeviceUpdateIntent(getAdapter().getContext());
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos
|
||||
|
||||
public class JsonPutRequest extends FilePutRawRequest {
|
||||
public JsonPutRequest(JSONObject object, FossilHRWatchAdapter adapter) {
|
||||
super((short)(0x0500 | adapter.getJsonIndex()), object.toString().getBytes(), adapter);
|
||||
super((short)(0x0500 | (adapter.getJsonIndex() & 0xFF)), object.toString().getBytes(), adapter);
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,16 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomWidget {
|
||||
public class CustomWidget extends Widget {
|
||||
private ArrayList<CustomWidgetElement> elements = new ArrayList<>();
|
||||
private int angle, distance;
|
||||
private String name;
|
||||
|
||||
public CustomWidget(int angle, int distance) {
|
||||
public CustomWidget(String name, int angle, int distance) {
|
||||
super(null, angle, distance);
|
||||
this.angle = angle;
|
||||
this.distance = distance;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getAngle() {
|
||||
@ -22,7 +25,23 @@ public class CustomWidget {
|
||||
return distance;
|
||||
}
|
||||
|
||||
public Collection<CustomWidgetElement> getElements(){
|
||||
public void setElements(ArrayList<CustomWidgetElement> elements) {
|
||||
this.elements = elements;
|
||||
}
|
||||
|
||||
public void setAngle(int angle) {
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
public void setDistance(int distance) {
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ArrayList<CustomWidgetElement> getElements(){
|
||||
return this.elements;
|
||||
}
|
||||
|
||||
@ -49,4 +68,8 @@ public class CustomWidget {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,37 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget;
|
||||
|
||||
public class CustomWidgetElement {
|
||||
import java.io.Serializable;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
public class CustomWidgetElement implements Serializable {
|
||||
public enum WidgetElementType {
|
||||
TYPE_TEXT,
|
||||
TYPE_IMAGE,
|
||||
TYPE_BACKGROUND
|
||||
TYPE_TEXT(R.id.qhybrid_widget_elements_type_text, "text"),
|
||||
TYPE_IMAGE(0, "image"),
|
||||
TYPE_BACKGROUND(R.id.qhybrid_widget_elements_type_background, "background");
|
||||
|
||||
private String jsonIdentifier;
|
||||
private int radioButtonResource;
|
||||
|
||||
WidgetElementType(int radioButtonResource, String jsonIdentifier){
|
||||
this.radioButtonResource = radioButtonResource;
|
||||
this.jsonIdentifier = jsonIdentifier;
|
||||
}
|
||||
|
||||
public int getRadioButtonResource() {
|
||||
return radioButtonResource;
|
||||
}
|
||||
|
||||
public String getJsonIdentifier() {
|
||||
return jsonIdentifier;
|
||||
}
|
||||
|
||||
static public WidgetElementType fromRadioButtonRessource(int radioButtonResource){
|
||||
for(WidgetElementType type : values()){
|
||||
if(type.getRadioButtonResource() == radioButtonResource) return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public final static int X_CENTER = 38;
|
||||
@ -15,6 +42,22 @@ public class CustomWidgetElement {
|
||||
private String id, value;
|
||||
private int x, y;
|
||||
|
||||
public void setWidgetElementType(WidgetElementType widgetElementType) {
|
||||
this.widgetElementType = widgetElementType;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
protected CustomWidgetElement(WidgetElementType widgetElementType, String id, String value, int x, int y) {
|
||||
this.widgetElementType = widgetElementType;
|
||||
this.id = id;
|
||||
|
@ -5,12 +5,18 @@ import androidx.annotation.NonNull;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public abstract class Widget {
|
||||
import java.io.Serializable;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
public class Widget implements Serializable {
|
||||
private WidgetType widgetType;
|
||||
int angle, distance;
|
||||
|
||||
public Widget(WidgetType type, int angle, int distance){
|
||||
public Widget(WidgetType type, int angle, int distance) {
|
||||
this.widgetType = type;
|
||||
this.angle = angle;
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -19,7 +25,7 @@ public abstract class Widget {
|
||||
return toJson().toString();
|
||||
}
|
||||
|
||||
public JSONObject toJson(){
|
||||
public JSONObject toJson() {
|
||||
JSONObject object = new JSONObject();
|
||||
|
||||
try {
|
||||
@ -27,13 +33,13 @@ public abstract class Widget {
|
||||
.put("name", widgetType.getIdentifier())
|
||||
.put("pos",
|
||||
new JSONObject()
|
||||
.put("angle", angle)
|
||||
.put("distance", distance)
|
||||
)
|
||||
.put("angle", angle)
|
||||
.put("distance", distance)
|
||||
)
|
||||
.put("data", new JSONObject())
|
||||
.put("theme",
|
||||
new JSONObject()
|
||||
.put("font_color", "default")
|
||||
.put("font_color", "default")
|
||||
);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
@ -43,17 +49,35 @@ public abstract class Widget {
|
||||
}
|
||||
|
||||
|
||||
enum WidgetType{
|
||||
TIMEZONE("timeZone2SSE");
|
||||
public enum WidgetType {
|
||||
HEART_RATE("hrSSE", R.string.hr_widget_heart_rate),
|
||||
STEPS("stepsSSE", R.string.hr_widget_steps),
|
||||
DATE("dateSSE", R.string.hr_widget_date),
|
||||
ACTIVE_MINUTES("activeMinutesSSE", R.string.hr_widget_active_minutes),
|
||||
CALORIES("caloriesSSE", R.string.hr_widget_calories),
|
||||
BATTERY("batterySSE", R.string.hr_widget_battery),
|
||||
NOTHING(null, R.string.hr_widget_nothing);
|
||||
|
||||
private String identifier;
|
||||
private int stringResource;
|
||||
|
||||
|
||||
WidgetType(String identifier){
|
||||
WidgetType(String identifier, int stringResource) {
|
||||
this.identifier = identifier;
|
||||
this.stringResource = stringResource;
|
||||
}
|
||||
|
||||
public String getIdentifier(){
|
||||
public static WidgetType fromJsonIdentifier(String jsonIdentifier){
|
||||
for(WidgetType type : values()){
|
||||
if(type.getIdentifier() != null && type.getIdentifier().equals(jsonIdentifier)) return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getStringResource() {
|
||||
return stringResource;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return this.identifier;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,11 @@ public class WidgetsPutRequest extends JsonPutRequest {
|
||||
|
||||
private static JSONObject prepareFile(Widget[] widgets){
|
||||
try {
|
||||
JSONArray widgetArray = new JSONArray(widgets);
|
||||
JSONArray widgetArray = new JSONArray();
|
||||
|
||||
for(Widget widget : widgets){
|
||||
widgetArray.put(widget.toJson());
|
||||
}
|
||||
|
||||
JSONObject object = new JSONObject()
|
||||
.put(
|
||||
|
@ -37,4 +37,51 @@
|
||||
android:id="@+id/qhybrid_button_bottom_single_press"
|
||||
android:textSize="20dp"/>
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="20dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="top widget"
|
||||
android:id="@+id/qhybrid_button_widget_top"
|
||||
android:textSize="20dp"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="right widget"
|
||||
android:id="@+id/qhybrid_button_widget_right"
|
||||
android:textSize="20dp"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="bottom widget"
|
||||
android:id="@+id/qhybrid_button_widget_bottom"
|
||||
android:textSize="20dp"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="left widget"
|
||||
android:id="@+id/qhybrid_button_widget_left"
|
||||
android:textSize="20dp"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="custom widgets" />
|
||||
|
||||
<ListView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="0.4"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/qhybrid_widget_list"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="add widget"
|
||||
android:id="@+id/qhybrid_widget_add"/>
|
||||
|
||||
</LinearLayout>
|
73
app/src/main/res/layout/qhybrid_activity_widget_settings.xml
Normal file
73
app/src/main/res/layout/qhybrid_activity_widget_settings.xml
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".devices.qhybrid.WidgetSettingsActivity">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:weightSum="1">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="widget name" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/qhybrid_widget_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="elements" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/qhybrid_widget_elements_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="0.4" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/qhybrid_widget_elements_add"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="add element" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:weightSum="1">
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/qhybrid_widget_delete"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="delete"
|
||||
android:layout_weight="0.5" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/qhybrid_widget_save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="save"
|
||||
android:layout_weight="0.5" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
79
app/src/main/res/layout/qhybrid_element_popup_view.xml
Normal file
79
app/src/main/res/layout/qhybrid_element_popup_view.xml
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="element id" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/qhybrid_widget_element_id"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="default value" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/qhybrid_widget_element_value"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="type" />
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/qhybrid_widget_element_type"
|
||||
android:checkedButton="@id/qhybrid_widget_elements_type_text">
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="text"
|
||||
android:id="@+id/qhybrid_widget_elements_type_text"/>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="background image"
|
||||
android:id="@+id/qhybrid_widget_elements_type_background" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="position" />
|
||||
|
||||
<RadioGroup
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/qhybrid_widget_element_position"
|
||||
android:checkedButton="@id/qhybrid_widget_elements_position_uppper">
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="upper half"
|
||||
android:id="@+id/qhybrid_widget_elements_position_uppper"/>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="lower half"
|
||||
android:id="@+id/qhybrid_widget_elements_position_lower" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
@ -773,6 +773,13 @@
|
||||
<string name="qhybrid_offset_timezone">offset timezone by</string>
|
||||
<string name="qhybrid_changes_delay_prompt">change might take some seconds…</string>
|
||||
<string name="qhybrid_offset_time_by">offset time by</string>
|
||||
<string name="hr_widget_heart_rate">Heart rate</string>
|
||||
<string name="hr_widget_steps">Steps</string>
|
||||
<string name="hr_widget_date">Date</string>
|
||||
<string name="hr_widget_active_minutes">Active minutes</string>
|
||||
<string name="hr_widget_calories">Calories</string>
|
||||
<string name="hr_widget_battery">Battery</string>
|
||||
<string name="hr_widget_nothing">Nothing</string>
|
||||
<plurals name="widget_alarm_target_hours">
|
||||
<item quantity="one">%d hour</item>
|
||||
<item quantity="two">%d hours</item>
|
||||
|
Loading…
Reference in New Issue
Block a user