mirror of
https://github.com/oliexdev/openScale.git
synced 2025-09-02 21:02:48 +02:00
Add measurement widget
The widget can be added to the home screen and can be configured to show any of the measurements that are enabled. It can also be resized from 1x1 to <max width>x1, adapting to the size change and showing a reasonable amount of information at each size. The default size is 4x1.
This commit is contained in:
@@ -15,6 +15,7 @@ Install [openScale-dev-build.apk](https://github.com/oliexdev/openScale/releases
|
||||
# Features
|
||||
|
||||
- Logs your body metrics (weight, body fat, body water, muscle percentage, lean body mass, bone mass, BMI, BMR, waist/hip circumference, waist-hip ratio, waist-to-height ratio)
|
||||
- Widget that can be added to the home screen showing any of the available metrics
|
||||
- Keep track of your diet process
|
||||
- Display all your data on a chart and table
|
||||
- Import or export your data from/into a CSV file
|
||||
|
@@ -36,6 +36,20 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".gui.widget.WidgetProvider">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_info" />
|
||||
</receiver>
|
||||
|
||||
<activity android:name=".gui.widget.WidgetConfigure">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
|
@@ -16,10 +16,13 @@
|
||||
|
||||
package com.health.openscale.core;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||
import android.arch.persistence.room.Room;
|
||||
import android.arch.persistence.room.RoomDatabase;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabaseCorruptException;
|
||||
@@ -52,6 +55,7 @@ import com.health.openscale.gui.views.FatMeasurementView;
|
||||
import com.health.openscale.gui.views.LBMMeasurementView;
|
||||
import com.health.openscale.gui.views.MeasurementViewSettings;
|
||||
import com.health.openscale.gui.views.WaterMeasurementView;
|
||||
import com.health.openscale.gui.widget.WidgetProvider;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
@@ -166,6 +170,17 @@ public class OpenScale {
|
||||
scaleDB.close();
|
||||
}
|
||||
|
||||
public void triggerWidgetUpdate() {
|
||||
int[] ids = AppWidgetManager.getInstance(context).getAppWidgetIds(
|
||||
new ComponentName(context, WidgetProvider.class));
|
||||
if (ids.length > 0) {
|
||||
Intent intent = new Intent(context, WidgetProvider.class);
|
||||
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public int addScaleUser(final ScaleUser user) {
|
||||
return (int)userDAO.insert(user);
|
||||
}
|
||||
@@ -247,6 +262,9 @@ public class OpenScale {
|
||||
return scaleMeasurementList;
|
||||
}
|
||||
|
||||
public ScaleMeasurement getLatestScaleMeasurement(int userId) {
|
||||
return measurementDAO.getLatest(userId);
|
||||
}
|
||||
|
||||
public ScaleMeasurement[] getTupleScaleData(int id)
|
||||
{
|
||||
@@ -324,6 +342,7 @@ public class OpenScale {
|
||||
}
|
||||
alarmHandler.entryChanged(context, scaleMeasurement);
|
||||
updateScaleData();
|
||||
triggerWidgetUpdate();
|
||||
} else {
|
||||
if (!silent) {
|
||||
Toast.makeText(context, context.getString(R.string.info_new_data_duplicated), Toast.LENGTH_LONG).show();
|
||||
@@ -374,6 +393,7 @@ public class OpenScale {
|
||||
alarmHandler.entryChanged(context, scaleMeasurement);
|
||||
|
||||
updateScaleData();
|
||||
triggerWidgetUpdate();
|
||||
}
|
||||
|
||||
public void deleteScaleData(int id)
|
||||
|
@@ -47,6 +47,9 @@ public interface ScaleMeasurementDAO {
|
||||
@Query("SELECT * FROM scaleMeasurements WHERE datetime >= :startYear AND datetime < :endYear AND userId = :userId AND enabled = 1 ORDER BY datetime DESC")
|
||||
List<ScaleMeasurement> getAllInRange(Date startYear, Date endYear, int userId);
|
||||
|
||||
@Query("SELECT * FROM scaleMeasurements WHERE userId = :userId AND enabled = 1 ORDER BY datetime DESC LIMIT 1")
|
||||
ScaleMeasurement getLatest(int userId);
|
||||
|
||||
@Insert (onConflict = OnConflictStrategy.IGNORE)
|
||||
long insert(ScaleMeasurement measurement);
|
||||
|
||||
|
@@ -196,6 +196,7 @@ public class MainActivity extends BaseAppCompatActivity
|
||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||
if (settingsActivityRunning) {
|
||||
recreate();
|
||||
OpenScale.getInstance().triggerWidgetUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -284,7 +284,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
||||
|
||||
SpannableStringBuilder string = new SpannableStringBuilder();
|
||||
string.append(visibleMeasurements.get(i).getValueAsString(false));
|
||||
visibleMeasurements.get(i).appendDiffValue(string);
|
||||
visibleMeasurements.get(i).appendDiffValue(string, true);
|
||||
|
||||
stringCache[position][i] = string;
|
||||
}
|
||||
|
@@ -405,7 +405,7 @@ public abstract class FloatMeasurementView extends MeasurementView {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDiffValue(SpannableStringBuilder text) {
|
||||
public void appendDiffValue(SpannableStringBuilder text, boolean newLine) {
|
||||
if (previousValue < 0.0f) {
|
||||
return;
|
||||
}
|
||||
@@ -425,7 +425,9 @@ public abstract class FloatMeasurementView extends MeasurementView {
|
||||
color = Color.GRAY;
|
||||
}
|
||||
|
||||
text.append('\n');
|
||||
if (newLine) {
|
||||
text.append('\n');
|
||||
}
|
||||
int start = text.length();
|
||||
text.append(symbol);
|
||||
text.setSpan(new ForegroundColorSpan(color), start, text.length(),
|
||||
|
@@ -65,6 +65,7 @@ public abstract class MeasurementView extends TableLayout {
|
||||
|
||||
private TableRow measurementRow;
|
||||
private ImageView iconView;
|
||||
private int iconId;
|
||||
private TextView nameView;
|
||||
private TextView valueView;
|
||||
private LinearLayout incDecLayout;
|
||||
@@ -84,6 +85,7 @@ public abstract class MeasurementView extends TableLayout {
|
||||
initView(context);
|
||||
|
||||
nameView.setText(textId);
|
||||
this.iconId = iconId;
|
||||
iconView.setImageResource(iconId);
|
||||
}
|
||||
|
||||
@@ -256,8 +258,9 @@ public abstract class MeasurementView extends TableLayout {
|
||||
|
||||
public CharSequence getName() { return nameView.getText(); }
|
||||
public abstract String getValueAsString(boolean withUnit);
|
||||
public void appendDiffValue(SpannableStringBuilder builder) { }
|
||||
public void appendDiffValue(SpannableStringBuilder builder, boolean newLine) { }
|
||||
public Drawable getIcon() { return iconView.getDrawable(); }
|
||||
public int getIconResource() { return iconId; }
|
||||
|
||||
protected boolean isEditable() {
|
||||
return true;
|
||||
|
@@ -0,0 +1,120 @@
|
||||
/* Copyright (C) 2018 Erik Johansson <erik@ejohansson.se>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.health.openscale.gui.widget;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TableRow;
|
||||
|
||||
import com.health.openscale.R;
|
||||
import com.health.openscale.core.OpenScale;
|
||||
import com.health.openscale.core.datatypes.ScaleUser;
|
||||
import com.health.openscale.gui.activities.BaseAppCompatActivity;
|
||||
import com.health.openscale.gui.views.MeasurementView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WidgetConfigure extends BaseAppCompatActivity {
|
||||
private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setResult(RESULT_CANCELED);
|
||||
|
||||
Intent intent = getIntent();
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
appWidgetId = extras.getInt(
|
||||
AppWidgetManager.EXTRA_APPWIDGET_ID,
|
||||
AppWidgetManager.INVALID_APPWIDGET_ID);
|
||||
}
|
||||
|
||||
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
|
||||
finish();
|
||||
}
|
||||
|
||||
setContentView(R.layout.widget_configuration);
|
||||
|
||||
OpenScale openScale = OpenScale.getInstance();
|
||||
|
||||
// Set up user spinner
|
||||
final Spinner userSpinner = findViewById(R.id.widget_user_spinner);
|
||||
List<String> users = new ArrayList<>();
|
||||
final List<Integer> userIds = new ArrayList<>();
|
||||
for (ScaleUser scaleUser : openScale.getScaleUserList()) {
|
||||
users.add(scaleUser.getUserName());
|
||||
userIds.add(scaleUser.getId());
|
||||
}
|
||||
ArrayAdapter<String> userAdapter = new ArrayAdapter<>(
|
||||
this, android.R.layout.simple_spinner_item, users);
|
||||
userAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
userSpinner.setAdapter(userAdapter);
|
||||
|
||||
// Hide user selector when there's only one user
|
||||
if (users.size() == 1) {
|
||||
TableRow row = (TableRow) userSpinner.getParent();
|
||||
row.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// Set up measurement spinner
|
||||
final Spinner measurementSpinner = findViewById(R.id.widget_measurement_spinner);
|
||||
List<String> measurements = new ArrayList<>();
|
||||
final List<String> measurementKeys = new ArrayList<>();
|
||||
for (MeasurementView measurementView : MeasurementView.getMeasurementList(
|
||||
this, MeasurementView.DateTimeOrder.NONE)) {
|
||||
if (measurementView.isVisible()) {
|
||||
measurements.add(measurementView.getName().toString());
|
||||
measurementKeys.add(measurementView.getKey());
|
||||
}
|
||||
}
|
||||
ArrayAdapter<String> measurementAdapter = new ArrayAdapter<>(
|
||||
this, android.R.layout.simple_spinner_item, measurements);
|
||||
measurementAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
measurementSpinner.setAdapter(measurementAdapter);
|
||||
|
||||
findViewById(R.id.widget_save).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int userId = userIds.get(userSpinner.getSelectedItemPosition());
|
||||
String measurementKey = measurementKeys.get(measurementSpinner.getSelectedItemPosition());
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit()
|
||||
.putInt(WidgetProvider.getUserIdPreferenceName(appWidgetId), userId)
|
||||
.putString(WidgetProvider.getMeasurementPreferenceName(appWidgetId), measurementKey)
|
||||
.apply();
|
||||
|
||||
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null);
|
||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {appWidgetId});
|
||||
sendBroadcast(intent);
|
||||
|
||||
Intent resultValue = new Intent();
|
||||
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
|
||||
setResult(RESULT_OK, resultValue);
|
||||
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,193 @@
|
||||
/* Copyright (C) 2018 Erik Johansson <erik@ejohansson.se>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.health.openscale.gui.widget;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.health.openscale.R;
|
||||
import com.health.openscale.core.OpenScale;
|
||||
import com.health.openscale.core.datatypes.ScaleMeasurement;
|
||||
import com.health.openscale.gui.MainActivity;
|
||||
import com.health.openscale.gui.activities.BaseAppCompatActivity;
|
||||
import com.health.openscale.gui.views.MeasurementView;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.List;
|
||||
|
||||
public class WidgetProvider extends AppWidgetProvider {
|
||||
List<MeasurementView> measurementViews;
|
||||
|
||||
public static final String getUserIdPreferenceName(int appWidgetId) {
|
||||
return String.format("widget_%d_userid", appWidgetId);
|
||||
}
|
||||
|
||||
public static final String getMeasurementPreferenceName(int appWidgetId) {
|
||||
return String.format("widget_%d_measurement", appWidgetId);
|
||||
}
|
||||
|
||||
private void updateWidget(Context context, AppWidgetManager appWidgetManager,
|
||||
int appWidgetId, Bundle newOptions) {
|
||||
// Make sure we use the correct language
|
||||
context = BaseAppCompatActivity.createBaseContext(context);
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
int userId = prefs.getInt(getUserIdPreferenceName(appWidgetId), -1);
|
||||
String key = prefs.getString(getMeasurementPreferenceName(appWidgetId), "");
|
||||
|
||||
if (measurementViews == null) {
|
||||
measurementViews = MeasurementView.getMeasurementList(
|
||||
context, MeasurementView.DateTimeOrder.NONE);
|
||||
}
|
||||
|
||||
MeasurementView measurementView = measurementViews.get(0);
|
||||
for (MeasurementView view : measurementViews) {
|
||||
if (view.getKey().equals(key)) {
|
||||
measurementView = view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenScale openScale = OpenScale.getInstance();
|
||||
ScaleMeasurement latest = openScale.getLatestScaleMeasurement(userId);
|
||||
if (latest != null) {
|
||||
ScaleMeasurement previous = openScale.getTupleScaleData(latest.getId())[0];
|
||||
measurementView.loadFrom(latest, previous);
|
||||
}
|
||||
|
||||
final int minWidth = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
|
||||
// From https://developer.android.com/guide/practices/ui_guidelines/widget_design
|
||||
final int twoCellsMinWidth = 110;
|
||||
final int thirdCellsMinWidth = 180;
|
||||
final int fourCellsMinWidth = 250;
|
||||
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
|
||||
|
||||
// Show icon in >= two cell mode
|
||||
if (minWidth >= twoCellsMinWidth) {
|
||||
views.setImageViewResource(R.id.widget_icon, measurementView.getIconResource());
|
||||
views.setViewVisibility(R.id.widget_icon, View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
views.setViewVisibility(R.id.widget_icon, View.GONE);
|
||||
}
|
||||
|
||||
// Show measurement name in >= four cell mode
|
||||
if (minWidth >= fourCellsMinWidth) {
|
||||
views.setTextViewText(R.id.widget_name, measurementView.getName());
|
||||
views.setTextViewText(R.id.widget_date,
|
||||
latest != null
|
||||
? DateFormat.getDateTimeInstance(
|
||||
DateFormat.LONG, DateFormat.SHORT).format(latest.getDateTime())
|
||||
: "");
|
||||
views.setViewVisibility(R.id.widget_name_date_layout, View.VISIBLE);
|
||||
}
|
||||
else {
|
||||
views.setViewVisibility(R.id.widget_name_date_layout, View.GONE);
|
||||
}
|
||||
|
||||
// Always show value, but use smaller font in once cell mode
|
||||
views.setTextViewText(R.id.widget_value, measurementView.getValueAsString(true));
|
||||
SpannableStringBuilder delta = new SpannableStringBuilder();
|
||||
measurementView.appendDiffValue(delta, false);
|
||||
views.setTextViewText(R.id.widget_delta, delta.toString());
|
||||
|
||||
if (minWidth >= thirdCellsMinWidth) {
|
||||
views.setTextViewTextSize(R.id.widget_value, TypedValue.COMPLEX_UNIT_DIP, 18);
|
||||
views.setTextViewTextSize(R.id.widget_delta, TypedValue.COMPLEX_UNIT_DIP, 17);
|
||||
}
|
||||
else if (minWidth >= twoCellsMinWidth) {
|
||||
views.setTextViewTextSize(R.id.widget_value, TypedValue.COMPLEX_UNIT_DIP, 17);
|
||||
views.setTextViewTextSize(R.id.widget_delta, TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||
}
|
||||
else {
|
||||
views.setTextViewTextSize(R.id.widget_value, TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||
views.setTextViewTextSize(R.id.widget_delta, TypedValue.COMPLEX_UNIT_DIP, 13);
|
||||
}
|
||||
|
||||
// Start main activity when widget is clicked
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.widget_layout, pendingIntent);
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
Bundle newOptions = appWidgetManager.getAppWidgetOptions(appWidgetId);
|
||||
updateWidget(context, appWidgetManager, appWidgetId, newOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,
|
||||
int appWidgetId, Bundle newOptions) {
|
||||
updateWidget(context, appWidgetManager, appWidgetId, newOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleted(Context context, int[] appWidgetIds) {
|
||||
SharedPreferences.Editor editor =
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit();
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
editor.remove(getUserIdPreferenceName(appWidgetId));
|
||||
editor.remove(getMeasurementPreferenceName(appWidgetId));
|
||||
}
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisabled(Context context) {
|
||||
measurementViews = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
for (int i = 0; i < oldWidgetIds.length; ++i) {
|
||||
String oldKey = getUserIdPreferenceName(oldWidgetIds[i]);
|
||||
if (prefs.contains(oldKey)) {
|
||||
editor.putInt(getUserIdPreferenceName(newWidgetIds[i]),
|
||||
prefs.getInt(oldKey, -1));
|
||||
editor.remove(oldKey);
|
||||
}
|
||||
|
||||
oldKey = getMeasurementPreferenceName(oldWidgetIds[i]);
|
||||
if (prefs.contains(oldKey)) {
|
||||
editor.putString(getMeasurementPreferenceName(newWidgetIds[i]),
|
||||
prefs.getString(oldKey, ""));
|
||||
editor.remove(oldKey);
|
||||
}
|
||||
}
|
||||
|
||||
editor.apply();
|
||||
}
|
||||
}
|
BIN
android_app/app/src/main/res/drawable-hdpi/appwidget_bg.9.png
Normal file
BIN
android_app/app/src/main/res/drawable-hdpi/appwidget_bg.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
BIN
android_app/app/src/main/res/drawable-mdpi/appwidget_bg.9.png
Normal file
BIN
android_app/app/src/main/res/drawable-mdpi/appwidget_bg.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
BIN
android_app/app/src/main/res/drawable-xhdpi/appwidget_bg.9.png
Normal file
BIN
android_app/app/src/main/res/drawable-xhdpi/appwidget_bg.9.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
81
android_app/app/src/main/res/layout/widget.xml
Normal file
81
android_app/app/src/main/res/layout/widget.xml
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingTop="8dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/widget_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/appwidget_bg"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/widget_icon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:maxWidth="40dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingStart="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/widget_name_date_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="3"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/widget_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textColor="@color/widgetTextColor"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
<TextView
|
||||
android:id="@+id/widget_date"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:textColor="@color/widgetTextColor"
|
||||
android:textSize="13sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="2"
|
||||
android:minWidth="40dp"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingStart="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/widget_value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
android:textColor="@color/widgetTextColor"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/widget_delta"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="right"
|
||||
android:lines="1"
|
||||
android:textColor="@color/widgetTextColor" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
56
android_app/app/src/main/res/layout/widget_configuration.xml
Normal file
56
android_app/app/src/main/res/layout/widget_configuration.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_configure_widget" />
|
||||
|
||||
<TableLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dp"
|
||||
android:stretchColumns="*">
|
||||
|
||||
<TableRow
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_select_user" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/widget_user_spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_select_measurement" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/widget_measurement_spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</TableRow>
|
||||
</TableLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/widget_save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save" />
|
||||
|
||||
</LinearLayout>
|
@@ -7,4 +7,6 @@
|
||||
<color name="primaryColor">#000000</color>
|
||||
<color name="primaryLightColor">@android:color/holo_blue_light</color>
|
||||
<color name="primaryDarkColor">#000000</color>
|
||||
|
||||
<color name="widgetTextColor">#555</color>
|
||||
</resources>
|
||||
|
@@ -219,4 +219,7 @@
|
||||
<string name="label_development">Development</string>
|
||||
<string name="label_debug_log">Save debug log to file</string>
|
||||
<string name="label_your_bluetooth_scale">Your Bluetooth scale</string>
|
||||
<string name="label_select_measurement">Select measurement</string>
|
||||
<string name="label_select_user">Select user</string>
|
||||
<string name="label_configure_widget">Configure widget</string>
|
||||
</resources>
|
||||
|
10
android_app/app/src/main/res/xml/widget_info.xml
Normal file
10
android_app/app/src/main/res/xml/widget_info.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:minWidth="250dp"
|
||||
android:minHeight="40dp"
|
||||
android:minResizeWidth="40dp"
|
||||
android:updatePeriodMillis="0"
|
||||
android:configure="com.health.openscale.gui.widget.WidgetConfigure"
|
||||
android:initialLayout="@layout/widget"
|
||||
android:resizeMode="horizontal"
|
||||
android:widgetCategory="home_screen">
|
||||
</appwidget-provider>
|
Reference in New Issue
Block a user