mirror of
https://github.com/oliexdev/openScale.git
synced 2025-08-21 07:51:46 +02:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -15,6 +15,7 @@ Install [openScale-dev-build.apk](https://github.com/oliexdev/openScale/releases
|
|||||||
# Features
|
# 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)
|
- 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
|
- Keep track of your diet process
|
||||||
- Display all your data on a chart and table
|
- Display all your data on a chart and table
|
||||||
- Import or export your data from/into a CSV file
|
- Import or export your data from/into a CSV file
|
||||||
|
@@ -36,6 +36,20 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</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
|
<provider
|
||||||
android:name="android.support.v4.content.FileProvider"
|
android:name="android.support.v4.content.FileProvider"
|
||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
@@ -16,10 +16,13 @@
|
|||||||
|
|
||||||
package com.health.openscale.core;
|
package com.health.openscale.core;
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.arch.persistence.db.SupportSQLiteDatabase;
|
import android.arch.persistence.db.SupportSQLiteDatabase;
|
||||||
import android.arch.persistence.room.Room;
|
import android.arch.persistence.room.Room;
|
||||||
import android.arch.persistence.room.RoomDatabase;
|
import android.arch.persistence.room.RoomDatabase;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabaseCorruptException;
|
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.LBMMeasurementView;
|
||||||
import com.health.openscale.gui.views.MeasurementViewSettings;
|
import com.health.openscale.gui.views.MeasurementViewSettings;
|
||||||
import com.health.openscale.gui.views.WaterMeasurementView;
|
import com.health.openscale.gui.views.WaterMeasurementView;
|
||||||
|
import com.health.openscale.gui.widget.WidgetProvider;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -166,6 +170,17 @@ public class OpenScale {
|
|||||||
scaleDB.close();
|
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) {
|
public int addScaleUser(final ScaleUser user) {
|
||||||
return (int)userDAO.insert(user);
|
return (int)userDAO.insert(user);
|
||||||
}
|
}
|
||||||
@@ -247,6 +262,9 @@ public class OpenScale {
|
|||||||
return scaleMeasurementList;
|
return scaleMeasurementList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ScaleMeasurement getLatestScaleMeasurement(int userId) {
|
||||||
|
return measurementDAO.getLatest(userId);
|
||||||
|
}
|
||||||
|
|
||||||
public ScaleMeasurement[] getTupleScaleData(int id)
|
public ScaleMeasurement[] getTupleScaleData(int id)
|
||||||
{
|
{
|
||||||
@@ -324,6 +342,7 @@ public class OpenScale {
|
|||||||
}
|
}
|
||||||
alarmHandler.entryChanged(context, scaleMeasurement);
|
alarmHandler.entryChanged(context, scaleMeasurement);
|
||||||
updateScaleData();
|
updateScaleData();
|
||||||
|
triggerWidgetUpdate();
|
||||||
} else {
|
} else {
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
Toast.makeText(context, context.getString(R.string.info_new_data_duplicated), Toast.LENGTH_LONG).show();
|
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);
|
alarmHandler.entryChanged(context, scaleMeasurement);
|
||||||
|
|
||||||
updateScaleData();
|
updateScaleData();
|
||||||
|
triggerWidgetUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteScaleData(int id)
|
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")
|
@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);
|
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)
|
@Insert (onConflict = OnConflictStrategy.IGNORE)
|
||||||
long insert(ScaleMeasurement measurement);
|
long insert(ScaleMeasurement measurement);
|
||||||
|
|
||||||
|
@@ -196,6 +196,7 @@ public class MainActivity extends BaseAppCompatActivity
|
|||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||||
if (settingsActivityRunning) {
|
if (settingsActivityRunning) {
|
||||||
recreate();
|
recreate();
|
||||||
|
OpenScale.getInstance().triggerWidgetUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -284,7 +284,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
|
|||||||
|
|
||||||
SpannableStringBuilder string = new SpannableStringBuilder();
|
SpannableStringBuilder string = new SpannableStringBuilder();
|
||||||
string.append(visibleMeasurements.get(i).getValueAsString(false));
|
string.append(visibleMeasurements.get(i).getValueAsString(false));
|
||||||
visibleMeasurements.get(i).appendDiffValue(string);
|
visibleMeasurements.get(i).appendDiffValue(string, true);
|
||||||
|
|
||||||
stringCache[position][i] = string;
|
stringCache[position][i] = string;
|
||||||
}
|
}
|
||||||
|
@@ -405,7 +405,7 @@ public abstract class FloatMeasurementView extends MeasurementView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendDiffValue(SpannableStringBuilder text) {
|
public void appendDiffValue(SpannableStringBuilder text, boolean newLine) {
|
||||||
if (previousValue < 0.0f) {
|
if (previousValue < 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -425,7 +425,9 @@ public abstract class FloatMeasurementView extends MeasurementView {
|
|||||||
color = Color.GRAY;
|
color = Color.GRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
text.append('\n');
|
if (newLine) {
|
||||||
|
text.append('\n');
|
||||||
|
}
|
||||||
int start = text.length();
|
int start = text.length();
|
||||||
text.append(symbol);
|
text.append(symbol);
|
||||||
text.setSpan(new ForegroundColorSpan(color), start, text.length(),
|
text.setSpan(new ForegroundColorSpan(color), start, text.length(),
|
||||||
|
@@ -20,6 +20,7 @@ import android.content.Context;
|
|||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
@@ -65,6 +66,7 @@ public abstract class MeasurementView extends TableLayout {
|
|||||||
|
|
||||||
private TableRow measurementRow;
|
private TableRow measurementRow;
|
||||||
private ImageView iconView;
|
private ImageView iconView;
|
||||||
|
private int iconId;
|
||||||
private TextView nameView;
|
private TextView nameView;
|
||||||
private TextView valueView;
|
private TextView valueView;
|
||||||
private LinearLayout incDecLayout;
|
private LinearLayout incDecLayout;
|
||||||
@@ -84,6 +86,7 @@ public abstract class MeasurementView extends TableLayout {
|
|||||||
initView(context);
|
initView(context);
|
||||||
|
|
||||||
nameView.setText(textId);
|
nameView.setText(textId);
|
||||||
|
this.iconId = iconId;
|
||||||
iconView.setImageResource(iconId);
|
iconView.setImageResource(iconId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,8 +259,9 @@ public abstract class MeasurementView extends TableLayout {
|
|||||||
|
|
||||||
public CharSequence getName() { return nameView.getText(); }
|
public CharSequence getName() { return nameView.getText(); }
|
||||||
public abstract String getValueAsString(boolean withUnit);
|
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 Drawable getIcon() { return iconView.getDrawable(); }
|
||||||
|
public int getIconResource() { return iconId; }
|
||||||
|
|
||||||
protected boolean isEditable() {
|
protected boolean isEditable() {
|
||||||
return true;
|
return true;
|
||||||
@@ -319,6 +323,11 @@ public abstract class MeasurementView extends TableLayout {
|
|||||||
return valueView.getCurrentTextColor();
|
return valueView.getCurrentTextColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getIndicatorColor() {
|
||||||
|
ColorDrawable background = (ColorDrawable)indicatorView.getBackground();
|
||||||
|
return background.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
protected void showEvaluatorRow(boolean show) {
|
protected void showEvaluatorRow(boolean show) {
|
||||||
if (show) {
|
if (show) {
|
||||||
evaluatorRow.setVisibility(View.VISIBLE);
|
evaluatorRow.setVisibility(View.VISIBLE);
|
||||||
|
@@ -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,198 @@
|
|||||||
|
/* 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);
|
||||||
|
|
||||||
|
views.setInt(R.id.indicator_view, "setBackgroundColor", measurementView.getIndicatorColor());
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
views.setViewVisibility(R.id.widget_icon_vertical, View.GONE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
views.setImageViewResource(R.id.widget_icon_vertical, measurementView.getIconResource());
|
||||||
|
views.setViewVisibility(R.id.widget_icon_vertical, View.VISIBLE);
|
||||||
|
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 |
94
android_app/app/src/main/res/layout/widget.xml
Normal file
94
android_app/app/src/main/res/layout/widget.xml
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<?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">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/widget_icon_vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingBottom="8dp" />
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/indicator_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="0.2" />
|
||||||
|
|
||||||
|
</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="primaryColor">#000000</color>
|
||||||
<color name="primaryLightColor">@android:color/holo_blue_light</color>
|
<color name="primaryLightColor">@android:color/holo_blue_light</color>
|
||||||
<color name="primaryDarkColor">#000000</color>
|
<color name="primaryDarkColor">#000000</color>
|
||||||
|
|
||||||
|
<color name="widgetTextColor">#555</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -220,4 +220,7 @@
|
|||||||
<string name="label_development">Development</string>
|
<string name="label_development">Development</string>
|
||||||
<string name="label_debug_log">Save debug log to file</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_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>
|
</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