diff --git a/.travis.yml b/.travis.yml index dcc74e712..d4f958ff3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ android: components: - platform-tools - tools - - build-tools-25.0.2 + - build-tools-26.0.2 - android-24 - extra-android-m2repository @@ -23,4 +23,4 @@ after_success: - chmod +x ./upload_apk.sh - ./upload_apk.sh -script: cd android_app && ./gradlew assembleDebug \ No newline at end of file +script: cd android_app && ./gradlew assembleDebug diff --git a/README.md b/README.md index 944e62a6a..facf2d842 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Please see in the [openScale wiki](https://github.com/oliexdev/openScale/wiki/Su If you found a bug, have an idea how to improve the openScale app or have a question, please create new issue or comment existing one. If you would like to contribute code, fork the repository and send a pull request. -If you want to help to support your Bluetooth scale please see [here](https://github.com/oliexdev/openScale/wiki/How-to-reverse-engineer-a-Blueeoth-4.x-scale) for further information. +If you want to help to support your Bluetooth scale please see [here](https://github.com/oliexdev/openScale/wiki/How-to-reverse-engineer-a-Bluetooth-4.x-scale) for further information. # Screens diff --git a/android_app/app/build.gradle b/android_app/app/build.gradle index d50a65a08..c8e856361 100644 --- a/android_app/app/build.gradle +++ b/android_app/app/build.gradle @@ -2,7 +2,6 @@ apply plugin: 'com.android.application' android { compileSdkVersion 24 - buildToolsVersion '25.0.2' defaultConfig { applicationId "com.health.openscale" diff --git a/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java b/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java index d60b178a6..d88f82531 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java +++ b/android_app/app/src/main/java/com/health/openscale/core/OpenScale.java @@ -52,40 +52,40 @@ public class OpenScale { - private static OpenScale instance; + private static OpenScale instance; - private ScaleDatabase scaleDB; + private ScaleDatabase scaleDB; private ScaleUserDatabase scaleUserDB; - private ArrayList scaleDataList; + private ArrayList scaleDataList; - private BluetoothCommunication btCom; - private String btDeviceName; + private BluetoothCommunication btCom; + private String btDeviceName; private AlarmHandler alarmHandler; - private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm"); + private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm"); private Context context; private ArrayList fragmentList; - private OpenScale(Context context) { + private OpenScale(Context context) { this.context = context; - scaleDB = new ScaleDatabase(context); + scaleDB = new ScaleDatabase(context); scaleUserDB = new ScaleUserDatabase(context); alarmHandler = new AlarmHandler(); btCom = null; fragmentList = new ArrayList<>(); updateScaleData(); - } + } - public static OpenScale getInstance(Context context) { - if (instance == null) { - instance = new OpenScale(context); - } + public static OpenScale getInstance(Context context) { + if (instance == null) { + instance = new OpenScale(context); + } - return instance; - } + return instance; + } public void addScaleUser(String name, Date birthday, int body_height, int scale_unit, int gender, float initial_weight, float goal_weight, Date goal_date) { @@ -156,9 +156,9 @@ public void updateScaleUser(int id, String name, Date birthday, int body_height, } - public ArrayList getScaleDataList() { - return scaleDataList; - } + public ArrayList getScaleDataList() { + return scaleDataList; + } public ScaleData[] getTupleScaleData(long id) @@ -166,7 +166,7 @@ public ScaleData[] getTupleScaleData(long id) return scaleDB.getTupleDataEntry(getSelectedScaleUser().id, id); } - public int addScaleData(ScaleData scaleData) { + public int addScaleData(ScaleData scaleData) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); @@ -201,7 +201,7 @@ public int addScaleData(ScaleData scaleData) { scaleData.setFat(fatMetric.getFat(getScaleUser(scaleData.getUserId()), scaleData)); } - if (scaleDB.insertEntry(scaleData)) { + if (scaleDB.insertEntry(scaleData)) { ScaleUser scaleUser = getScaleUser(scaleData.getUserId()); String infoText = String.format(context.getString(R.string.info_new_data_added), scaleData.getConvertedWeight(scaleUser.scale_unit), scaleUser.UNIT_STRING[scaleUser.scale_unit], dateTimeFormat.format(scaleData.getDateTime()), scaleUser.user_name); @@ -211,7 +211,7 @@ public int addScaleData(ScaleData scaleData) { } return scaleData.getUserId(); - } + } private int getSmartUserAssignment(float weight, float range) { ArrayList scaleUser = getScaleUserList(); @@ -263,31 +263,31 @@ public void deleteScaleData(long id) updateScaleData(); } - public void importData(String filename) throws IOException { - File file = new File(filename); + public void importData(String filename) throws IOException { + File file = new File(filename); - FileInputStream inputStream = new FileInputStream(file); + FileInputStream inputStream = new FileInputStream(file); - InputStreamReader inputReader = new InputStreamReader(inputStream); - BufferedReader csvReader = new BufferedReader(inputReader); + InputStreamReader inputReader = new InputStreamReader(inputStream); + BufferedReader csvReader = new BufferedReader(inputReader); - String line = csvReader.readLine(); + String line = csvReader.readLine(); - try { - while (line != null) { - String csvField[] = line.split(",", -1); + try { + while (line != null) { + String csvField[] = line.split(",", -1); if (csvField.length < 9) { throw new IOException("Can't parse CSV file. Field length is wrong."); } - ScaleData newScaleData = new ScaleData(); + ScaleData newScaleData = new ScaleData(); - newScaleData.setDateTime(dateTimeFormat.parse(csvField[0])); - newScaleData.setWeight(Float.parseFloat(csvField[1])); - newScaleData.setFat(Float.parseFloat(csvField[2])); - newScaleData.setWater(Float.parseFloat(csvField[3])); - newScaleData.setMuscle(Float.parseFloat(csvField[4])); + newScaleData.setDateTime(dateTimeFormat.parse(csvField[0])); + newScaleData.setWeight(Float.parseFloat(csvField[1])); + newScaleData.setFat(Float.parseFloat(csvField[2])); + newScaleData.setWater(Float.parseFloat(csvField[3])); + newScaleData.setMuscle(Float.parseFloat(csvField[4])); newScaleData.setLBW(Float.parseFloat(csvField[5])); newScaleData.setBone(Float.parseFloat(csvField[6])); newScaleData.setWaist(Float.parseFloat(csvField[7])); @@ -296,37 +296,39 @@ public void importData(String filename) throws IOException { newScaleData.setUserId(getSelectedScaleUser().id); - scaleDB.insertEntry(newScaleData); + scaleDB.insertEntry(newScaleData); - line = csvReader.readLine(); - } + line = csvReader.readLine(); + } - } catch (ParseException e) { - throw new IOException("Can't parse date format. Please set the date time format as (e.g. 31.10.2014 05:23)"); - } catch (NumberFormatException e) { + } catch (ParseException e) { + throw new IOException("Can't parse date format. Please set the date time format as (e.g. 31.10.2014 05:23)"); + } catch (NumberFormatException e) { throw new IOException("Can't parse float number (" + e.getMessage()+")"); + } catch (ArrayIndexOutOfBoundsException e) { + throw new IOException("Can't parse format column number mismatch"); } updateScaleData(); - csvReader.close(); - inputReader.close(); - } + csvReader.close(); + inputReader.close(); + } - public void exportData(String filename) throws IOException { - File file = new File(filename); - file.createNewFile(); + public void exportData(String filename) throws IOException { + File file = new File(filename); + file.createNewFile(); - FileOutputStream outputStream = new FileOutputStream(file); + FileOutputStream outputStream = new FileOutputStream(file); - OutputStreamWriter csvWriter = new OutputStreamWriter(outputStream); + OutputStreamWriter csvWriter = new OutputStreamWriter(outputStream); - for (ScaleData scaleData : scaleDataList) { - csvWriter.append(dateTimeFormat.format(scaleData.getDateTime()) + ","); - csvWriter.append(Float.toString(scaleData.getWeight()) + ","); - csvWriter.append(Float.toString(scaleData.getFat()) + ","); - csvWriter.append(Float.toString(scaleData.getWater()) + ","); - csvWriter.append(Float.toString(scaleData.getMuscle()) + ","); + for (ScaleData scaleData : scaleDataList) { + csvWriter.append(dateTimeFormat.format(scaleData.getDateTime()) + ","); + csvWriter.append(Float.toString(scaleData.getWeight()) + ","); + csvWriter.append(Float.toString(scaleData.getFat()) + ","); + csvWriter.append(Float.toString(scaleData.getWater()) + ","); + csvWriter.append(Float.toString(scaleData.getMuscle()) + ","); csvWriter.append(Float.toString(scaleData.getLBW()) + ","); csvWriter.append(Float.toString(scaleData.getBone()) + ","); csvWriter.append(Float.toString(scaleData.getWaist()) + ","); @@ -335,20 +337,20 @@ public void exportData(String filename) throws IOException { csvWriter.append(scaleData.getComment()); } - csvWriter.append("\n"); - } + csvWriter.append("\n"); + } - csvWriter.close(); - outputStream.close(); - } + csvWriter.close(); + outputStream.close(); + } - public void clearScaleData(int userId) { + public void clearScaleData(int userId) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); prefs.edit().putInt("uniqueNumber", 0x00).commit(); - scaleDB.clearScaleData(userId); + scaleDB.clearScaleData(userId); updateScaleData(); - } + } public int[] getCountsOfMonth(int year) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); @@ -371,8 +373,8 @@ public ArrayList getScaleDataOfYear(int year) { return scaleDB.getScaleDataOfYear(selectedUserId, year); } - public boolean startSearchingForBluetooth(String deviceName, Handler callbackBtHandler) { - Log.d("OpenScale", "Bluetooth Server started! I am searching for device ..."); + public boolean startSearchingForBluetooth(String deviceName, Handler callbackBtHandler) { + Log.d("OpenScale", "Bluetooth Server started! I am searching for device ..."); for (BluetoothCommunication.BT_DEVICE_ID btScaleID : BluetoothCommunication.BT_DEVICE_ID.values()) { btCom = BluetoothCommunication.getBtDevice(context, btScaleID); @@ -390,12 +392,12 @@ public boolean startSearchingForBluetooth(String deviceName, Handler callbackBtH return false; } - public void stopSearchingForBluetooth() { - if (btCom != null) { + public void stopSearchingForBluetooth() { + if (btCom != null) { btCom.stopSearching(); Log.d("OpenScale", "Bluetooth Server explicit stopped!"); - } - } + } + } public void registerFragment(FragmentUpdateListener fragment) { fragmentList.add(fragment); @@ -415,7 +417,7 @@ public void updateScaleData() scaleDataList = scaleDB.getScaleDataList(selectedUserId); - for(FragmentUpdateListener fragment : fragmentList) { + for (FragmentUpdateListener fragment : fragmentList) { if (fragment != null) { if (((Fragment)fragment).isAdded()) { fragment.updateOnView(scaleDataList); diff --git a/android_app/app/src/main/java/com/health/openscale/core/alarm/AlarmHandler.java b/android_app/app/src/main/java/com/health/openscale/core/alarm/AlarmHandler.java index 1e35ae3ad..a5ea914a2 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/alarm/AlarmHandler.java +++ b/android_app/app/src/main/java/com/health/openscale/core/alarm/AlarmHandler.java @@ -59,10 +59,10 @@ public void entryChanged(Context context, ScaleData data) Calendar dataTimestamp = Calendar.getInstance(); dataTimestamp.setTimeInMillis(dataMillis); - if(AlarmHandler.isSameDate(dataTimestamp, Calendar.getInstance())) + if (AlarmHandler.isSameDate(dataTimestamp, Calendar.getInstance())) { cancelAlarmNotification(context); - cancelAndRescheduleAlarmForNextWeek( context, dataTimestamp ); + cancelAndRescheduleAlarmForNextWeek(context, dataTimestamp); } } diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java index 5d6b217a4..b07ca2ee2 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java @@ -38,7 +38,7 @@ public enum BT_STATUS_CODE {BT_RETRIEVE_SCALE_DATA, BT_INIT_PROCESS, BT_CONNECTI BT_CONNECTION_LOST, BT_NO_DEVICE_FOUND, BT_UNEXPECTED_ERROR, BT_SCALE_MESSAGE }; public enum BT_MACHINE_STATE {BT_INIT_STATE, BT_CMD_STATE, BT_CLEANUP_STATE} - public enum BT_DEVICE_ID {CUSTOM_OPENSCALE, MI_SCALE_V1, MI_SCALE_V2, SANITAS_SBF70, MEDISANA_BS444, DIGOO_DGS038H, EXCELVANT_CF369BLE, YUNMAI_MINI, YUNMAI_SE, MGB} + public enum BT_DEVICE_ID {CUSTOM_OPENSCALE, MI_SCALE_V1, MI_SCALE_V2, SANITAS_SBF70, MEDISANA_BS444, DIGOO_DGS038H, EXCELVANT_CF369BLE, YUNMAI_MINI, YUNMAI_SE, MGB, EXINGTECH_Y1} protected Context context; @@ -97,6 +97,8 @@ public static BluetoothCommunication getBtDevice(Context context, BT_DEVICE_ID b return new BluetoothYunmaiSE(context); case MGB: return new BluetoothMGB(context); + case EXINGTECH_Y1: + return new BluetoothExingtechY1(context); } return null; @@ -240,7 +242,7 @@ protected void setNextCmd(int nextCommand) { * @param gattCharacteristic the Bluetooth Gatt characteristic * @param status the status code */ - protected void onBluetoothDataRead(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic, int status){}; + protected void onBluetoothDataRead(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic, int status) {}; /** * Method is triggered if a Bluetooth data from a device is notified or indicated. @@ -248,7 +250,7 @@ protected void setNextCmd(int nextCommand) { * @param bluetoothGatt the Bluetooth Gatt * @param gattCharacteristic the Bluetooth characteristic */ - protected void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic){}; + protected void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) {}; /** * Set the Bluetooth machine state to a specific state. @@ -369,7 +371,7 @@ protected String byteInHex(byte[] data) { } final StringBuilder stringBuilder = new StringBuilder(data.length); - for(byte byteChar : data) { + for (byte byteChar : data) { stringBuilder.append(String.format("%02X ", byteChar)); } diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCustomOpenScale.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCustomOpenScale.java index 386ca8365..8220918e2 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCustomOpenScale.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCustomOpenScale.java @@ -142,7 +142,7 @@ public void stopSearching() { btConnectThread = null; } } - + public void clearEEPROM() { sendBtData("9"); diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothDigooDGSO38H.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothDigooDGSO38H.java index b82ffd3ad..5b492d34c 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothDigooDGSO38H.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothDigooDGSO38H.java @@ -133,7 +133,7 @@ private void parseBytes(byte[] weightBytes) { ScaleData scaleBtData = new ScaleData(); weight = (float) (((weightBytes[3] & 0xFF) << 8) | (weightBytes[4] & 0xFF)) / 100.0f; fat = (float) (((weightBytes[6] & 0xFF) << 8) | (weightBytes[7] & 0xFF)) / 10.0f; - if(Math.abs(fat - 0.0) < 0.00001) { + if (Math.abs(fat - 0.0) < 0.00001) { Log.d("BluetoothDigooDGSO38H", "Scale signaled that measurement of all data " + "is done, but fat ist still zero. Settling for just adding weight."); } else { diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothExingtechY1.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothExingtechY1.java new file mode 100644 index 000000000..ff144eb46 --- /dev/null +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothExingtechY1.java @@ -0,0 +1,128 @@ +/* Copyright (C) 2017 olie.xdev +* +* 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 +*/ + +package com.health.openscale.core.bluetooth; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import com.health.openscale.core.OpenScale; +import com.health.openscale.core.datatypes.ScaleData; +import com.health.openscale.core.datatypes.ScaleUser; + +import java.util.Date; +import java.util.UUID; + +public class BluetoothExingtechY1 extends BluetoothCommunication { + private final UUID WEIGHT_MEASUREMENT_SERVICE = UUID.fromString("f433bd80-75b8-11e2-97d9-0002a5d5c51b"); + private final UUID WEIGHT_MEASUREMENT_CHARACTERISTIC = UUID.fromString("1a2ea400-75b9-11e2-be05-0002a5d5c51b"); // read, notify + private final UUID CMD_MEASUREMENT_CHARACTERISTIC = UUID.fromString("29f11080-75b9-11e2-8bf6-0002a5d5c51b"); // write only + private final UUID WEIGHT_MEASUREMENT_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + public BluetoothExingtechY1(Context context) { + super(context); + } + + @Override + public String deviceName() { + return "Exingtech Y1"; + } + + @Override + public String defaultDeviceName() { + return "VScale"; + } + + @Override + boolean nextInitCmd(int stateNr) { + switch (stateNr) { + case 0: + setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_CHARACTERISTIC, WEIGHT_MEASUREMENT_CONFIG); + break; + case 1: + final ScaleUser selectedUser = OpenScale.getInstance(context).getSelectedScaleUser(); + + byte gender = selectedUser.isMale() ? (byte)0x00 : (byte)0x01; // 00 - male; 01 - female + byte height = (byte)(selectedUser.body_height & 0xff); // cm + byte age = (byte)(selectedUser.getAge(new Date()) & 0xff); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + int userId = prefs.getInt("selectedUserId", -1); + + byte cmdByte[] = {(byte)0x10, (byte)userId, gender, age, height}; + + writeBytes(WEIGHT_MEASUREMENT_SERVICE, CMD_MEASUREMENT_CHARACTERISTIC, cmdByte); + break; + default: + return false; + } + + return true; + } + + @Override + boolean nextBluetoothCmd(int stateNr) { + return false; + } + + @Override + boolean nextCleanUpCmd(int stateNr) { + return false; + } + + @Override + public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) { + final byte[] data = gattCharacteristic.getValue(); + + if (data != null && data.length > 0) { + // if data is body scale type + if (data[0] == (byte)0x01 && data.length == 20) { + parseBytes(data); + } + } + } + + private void parseBytes(byte[] weightBytes) { + int userId = (int)(weightBytes[0] & 0x0F); + int gender = (int)(weightBytes[1]); // 0x00 male; 0x01 female + int age = (int)(weightBytes[2]); // 10 ~ 99 + int height = (int)(weightBytes[3]); // 0 ~ 255 + float weight = (float) (((weightBytes[4] & 0xFF) << 8) | (weightBytes[5] & 0xFF)) / 10.0f; // kg + float fat = (float)(((weightBytes[6] & 0xFF) << 8) | (weightBytes[7] & 0xFF)) / 10.0f; // % + float water = (float)(((weightBytes[8] & 0xFF) << 8) | (weightBytes[9] & 0xFF)) / 10.0f; // % + float bone = (float)(((weightBytes[10] & 0xFF) << 8) | (weightBytes[11] & 0xFF)) / weight * 10.0f; // kg + float muscle = (float)(((weightBytes[12] & 0xFF) << 8) | (weightBytes[13] & 0xFF)) / 10.0f; // % + float visc_muscle = (float)(weightBytes[14] & 0xFF); // % + float calorie = (float)(((weightBytes[15] & 0xFF) << 8) | (weightBytes[16] & 0xFF)); + float bmi = (float)(((weightBytes[17] & 0xFF) << 8) | (weightBytes[18] & 0xFF)) / 10.0f; + + ScaleData scaleBtData = new ScaleData(); + + final ScaleUser selectedUser = OpenScale.getInstance(context).getSelectedScaleUser(); + + scaleBtData.setConvertedWeight(weight, selectedUser.scale_unit); + scaleBtData.setFat(fat); + scaleBtData.setMuscle(muscle); + scaleBtData.setWater(water); + scaleBtData.setBone(bone); + scaleBtData.setDateTime(new Date()); + + addScaleData(scaleBtData); + } +} diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMGB.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMGB.java index 0491be288..bef744001 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMGB.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMGB.java @@ -1,18 +1,18 @@ /* Copyright (C) 2014 olie.xdev * 2017 DreamNik * -* 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 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. +* 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 +* You should have received a copy of the GNU General Public License +* along with this program. If not, see */ package com.health.openscale.core.bluetooth; @@ -33,198 +33,195 @@ public class BluetoothMGB extends BluetoothCommunication { - static final UUID uuid_service = UUID.fromString("0000ffb0-0000-1000-8000-00805f9b34fb"); - static final UUID uuid_char_cfg = UUID.fromString("0000ffb1-0000-1000-8000-00805f9b34fb"); - static final UUID uuid_char_ctrl = UUID.fromString("0000ffb2-0000-1000-8000-00805f9b34fb"); - static final UUID uuid_desc_ctrl = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + static final UUID uuid_service = UUID.fromString("0000ffb0-0000-1000-8000-00805f9b34fb"); + static final UUID uuid_char_cfg = UUID.fromString("0000ffb1-0000-1000-8000-00805f9b34fb"); + static final UUID uuid_char_ctrl = UUID.fromString("0000ffb2-0000-1000-8000-00805f9b34fb"); + static final UUID uuid_desc_ctrl = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); - private Calendar now; - private ScaleUser user; - private ScaleData measurement; - private byte[] packet_buf; - private int packet_pos; + private Calendar now; + private ScaleUser user; + private ScaleData measurement; + private byte[] packet_buf; + private int packet_pos; - private int popInt( ){ - return packet_buf[packet_pos++] & 0xFF; - } + private int popInt() { + return packet_buf[packet_pos++] & 0xFF; + } - private float popFloat( ){ - int r = popInt(); - r = popInt() | (r<<8); - return r * 0.1f; - } + private float popFloat() { + int r = popInt(); + r = popInt() | (r<<8); + return r * 0.1f; + } - private void writeCfg( int b2 , int b3 , int b4 , int b5 ){ - byte[] buf = new byte[8]; - buf[0] = (byte)0xAC; - buf[1] = (byte)0x02; - buf[2] = (byte)b2; - buf[3] = (byte)b3; - buf[4] = (byte)b4; - buf[5] = (byte)b5; - buf[6] = (byte)0xCC; - buf[7] = (byte)( ( buf[2] + buf[3] + buf[4] + buf[5] + buf[6] ) & 0xFF ); + private void writeCfg(int b2, int b3, int b4, int b5) { + byte[] buf = new byte[8]; + buf[0] = (byte)0xAC; + buf[1] = (byte)0x02; + buf[2] = (byte)b2; + buf[3] = (byte)b3; + buf[4] = (byte)b4; + buf[5] = (byte)b5; + buf[6] = (byte)0xCC; + buf[7] = (byte)((buf[2] + buf[3] + buf[4] + buf[5] + buf[6]) & 0xFF); - writeBytes( uuid_service , uuid_char_cfg , buf ); - } + writeBytes(uuid_service, uuid_char_cfg, buf); + } + public BluetoothMGB(Context context) { + super(context); + } + @Override + public String deviceName() { + return "SWAN"; + } - public BluetoothMGB( Context context ){ - super(context); - } + @Override + public String defaultDeviceName() { + return "SWAN"; + } - @Override - public String deviceName() { - return "SWAN"; - } + @Override + public boolean checkDeviceName(String btDeviceName) { + if (btDeviceName.startsWith("SWAN")) { + return true; + } - @Override - public String defaultDeviceName() { - return "SWAN"; - } + return false; + } - @Override - public boolean checkDeviceName(String btDeviceName) { - if (btDeviceName.startsWith("SWAN")) { - return true; - } - return false; - } + @Override + boolean nextInitCmd(int stateNr) { + switch (stateNr) { + case 0: + setNotificationOn(uuid_service, uuid_char_ctrl, uuid_desc_ctrl); + now = Calendar.getInstance(); + user = OpenScale.getInstance(context).getSelectedScaleUser(); + break; + case 1: + writeCfg(0xF7, 0, 0, 0); + break; - @Override - boolean nextInitCmd(int stateNr) { - switch (stateNr) { - case 0: - setNotificationOn( uuid_service , uuid_char_ctrl , uuid_desc_ctrl ); - now = Calendar.getInstance(); - user = OpenScale.getInstance(context).getSelectedScaleUser(); - break; + case 2: + writeCfg(0xFA, 0, 0, 0); + break; - case 1: - writeCfg( 0xF7 , 0 , 0 , 0 ); - break; + case 3: + writeCfg(0xFB, (user.isMale() ? 1 : 2), user.getAge(new Date()), user.body_height); + break; - case 2: - writeCfg( 0xFA , 0 , 0 , 0 ); - break; + case 4: + writeCfg(0xFD, now.get(Calendar.YEAR) - 2000, now.get(Calendar.MONTH) - Calendar.JANUARY + 1, now.get(Calendar.DAY_OF_MONTH)); + break; - case 3: - writeCfg( 0xFB , (user.isMale() ? 1 : 2) , user.getAge(new Date()) , user.body_height ); - break; + case 5: + writeCfg(0xFC, now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), now.get(Calendar.SECOND)); + break; - case 4: - writeCfg( 0xFD , now.get( Calendar.YEAR ) - 2000 , now.get( Calendar.MONTH ) - Calendar.JANUARY + 1 , now.get( Calendar.DAY_OF_MONTH ) ); - break; + case 6: + writeCfg(0xFE, 6, 1, 0); + break; - case 5: - writeCfg( 0xFC , now.get( Calendar.HOUR_OF_DAY ) , now.get( Calendar.MINUTE ) , now.get( Calendar.SECOND ) ); - break; + default: + return false; + } - case 6: - writeCfg( 0xFE , 6 , 1 , 0 ); - break; + return true; + } - default: - return false; - } - return true; - } + @Override + boolean nextBluetoothCmd(int stateNr) { + return false; + } - @Override - boolean nextBluetoothCmd(int stateNr) { - return false; - } + @Override + boolean nextCleanUpCmd(int stateNr) { + return false; + } - @Override - boolean nextCleanUpCmd(int stateNr) { - return false; - } + @Override + public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) { + packet_buf = gattCharacteristic.getValue(); + packet_pos = 0; + if (packet_buf == null || packet_buf.length <= 0) { + return; + } - @Override - public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) { - packet_buf = gattCharacteristic.getValue(); - packet_pos = 0; + if (packet_buf.length != 20) { + return; + } - if( packet_buf == null || packet_buf.length <= 0 ){ - return; - } + int hdr_1 = popInt(); + int hdr_2 = popInt(); + int hdr_3 = popInt(); - if( packet_buf.length != 20 ){ - return; - } + if (hdr_1 == 0xAC && hdr_2 == 0x02 && hdr_3 == 0xFF) { + measurement = new ScaleData(); - int hdr_1 = popInt(); - int hdr_2 = popInt(); - int hdr_3 = popInt(); + popInt(); //unknown =00 + popInt(); //unknown =02 + popInt(); //unknown =21 - if( hdr_1 == 0xAC && hdr_2 == 0x02 && hdr_3 == 0xFF ){ - measurement = new ScaleData(); + popInt(); //Year + popInt(); //Month + popInt(); //Day + popInt(); //Hour + popInt(); //Minute + popInt(); //Second - popInt(); //unknown =00 - popInt(); //unknown =02 - popInt(); //unknown =21 + measurement.setDateTime(new Date()); - popInt(); //Year - popInt(); //Month - popInt(); //Day - popInt(); //Hour - popInt(); //Minute - popInt(); //Second + measurement.setWeight(popFloat()); - measurement.setDateTime( new Date() ); + popFloat(); //BMI - measurement.setWeight( popFloat() ); + measurement.setFat(popFloat()); - popFloat(); //BMI + popInt(); //unknown =00 + popInt(); //unknown =00 - measurement.setFat( popFloat() ); + } else if (hdr_1 == 0x01 && hdr_2 == 0x00) { + measurement.setMuscle(popFloat()); - popInt(); //unknown =00 - popInt(); //unknown =00 + popFloat(); //BMR - }else - if( hdr_1 == 0x01 && hdr_2 == 0x00 ){ - measurement.setMuscle( popFloat() ); + measurement.setBone(popFloat()); - popFloat(); //BMR + measurement.setWater(popFloat()); - measurement.setBone( popFloat() ); + popInt(); // Age - measurement.setWater( popFloat() ); + popFloat();// protein rate - popInt(); // Age + popInt(); // unknown =00 + popInt(); // unknown =01 + popInt(); // unknown =1b + popInt(); // unknown =a5 + popInt(); // unknown =02 + popInt(); // unknown =47;48;4e;4b;42 - popFloat();// protein rate + addScaleData(measurement); - popInt(); // unknown =00 - popInt(); // unknown =01 - popInt(); // unknown =1b - popInt(); // unknown =a5 - popInt(); // unknown =02 - popInt(); // unknown =47;48;4e;4b;42 - - addScaleData( measurement ); - - // Visceral fat? - // Standart weight? - // WeightControl? - // Body fat? - // Muscle weight? - } - } + // Visceral fat? + // Standart weight? + // WeightControl? + // Body fat? + // Muscle weight? + } + } } diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMedisanaBS444.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMedisanaBS444.java index eaad10873..2842c389d 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMedisanaBS444.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMedisanaBS444.java @@ -60,12 +60,12 @@ public boolean checkDeviceName(String btDeviceName) { } @Override - boolean nextInitCmd(int stateNr){ + boolean nextInitCmd(int stateNr) { return false; } @Override - boolean nextBluetoothCmd(int stateNr){ + boolean nextBluetoothCmd(int stateNr) { switch (stateNr) { case 0: // set indication on for feature characteristic @@ -82,7 +82,7 @@ boolean nextBluetoothCmd(int stateNr){ case 3: // send magic number to receive weight data Date date = new Date(); - int unix_timestamp = (int) ((date.getTime() / 1000) - 1262304000) ; // -40 years because unix time starts in year 1970 + int unix_timestamp = (int) ((date.getTime() / 1000) - 1262304000); // -40 years because unix time starts in year 1970 byte[] magicBytes = new byte[] { (byte)0x02, @@ -103,13 +103,13 @@ boolean nextBluetoothCmd(int stateNr){ } @Override - boolean nextCleanUpCmd(int stateNr){ + boolean nextCleanUpCmd(int stateNr) { return false; } @Override - public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic){ + public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) { final byte[] data = gattCharacteristic.getValue(); if (gattCharacteristic.getUuid().equals(WEIGHT_MEASUREMENT_CHARACTERISTIC)) { diff --git a/android_app/app/src/main/java/com/health/openscale/core/bodymetric/EstimatedFatMetric.java b/android_app/app/src/main/java/com/health/openscale/core/bodymetric/EstimatedFatMetric.java index 0ef9f6bcc..f943c0640 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bodymetric/EstimatedFatMetric.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bodymetric/EstimatedFatMetric.java @@ -21,7 +21,7 @@ public abstract class EstimatedFatMetric { public enum FORMULA { BF_DEURENBERG, BF_DEURENBERG_II, BF_EDDY, BF_GALLAGHER, BF_GALLAGHER_ASIAN }; - public static EstimatedFatMetric getEstimatedMetric( FORMULA metric) { + public static EstimatedFatMetric getEstimatedMetric(FORMULA metric) { switch (metric) { case BF_DEURENBERG: return new BFDeurenberg(); diff --git a/android_app/app/src/main/java/com/health/openscale/core/bodymetric/EstimatedWaterMetric.java b/android_app/app/src/main/java/com/health/openscale/core/bodymetric/EstimatedWaterMetric.java index f5e01be7e..33323a86e 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bodymetric/EstimatedWaterMetric.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bodymetric/EstimatedWaterMetric.java @@ -21,7 +21,7 @@ public abstract class EstimatedWaterMetric { public enum FORMULA { TBW_BEHNKE, TBW_DELWAIDECRENIER, TBW_HUMEWEYERS, TBW_LEESONGKIM }; - public static EstimatedWaterMetric getEstimatedMetric( FORMULA metric) { + public static EstimatedWaterMetric getEstimatedMetric(FORMULA metric) { switch (metric) { case TBW_BEHNKE: return new TBWBehnke(); diff --git a/android_app/app/src/main/java/com/health/openscale/core/database/ScaleDatabase.java b/android_app/app/src/main/java/com/health/openscale/core/database/ScaleDatabase.java index a5777d007..f90801bcd 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/database/ScaleDatabase.java +++ b/android_app/app/src/main/java/com/health/openscale/core/database/ScaleDatabase.java @@ -32,10 +32,10 @@ import java.util.Calendar; import java.util.Locale; -public class ScaleDatabase extends SQLiteOpenHelper { +public class ScaleDatabase extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 6; - private static final String DATABASE_NAME = "openScaleDatabase.db"; - + private static final String DATABASE_NAME = "openScaleDatabase.db"; + private static final String TABLE_NAME = "scaledata"; private static final String COLUMN_NAME_ID = "id"; private static final String COLUMN_NAME_USER_ID = "user_id"; @@ -50,26 +50,26 @@ public class ScaleDatabase extends SQLiteOpenHelper { private static final String COLUMN_NAME_HIP = "hip"; private static final String COLUMN_NAME_COMMENT = "comment"; private static final String COLUMN_NAME_ENABLE = "enable"; - - private static final String SQL_CREATE_ENTRIES = - "CREATE TABLE " + TABLE_NAME + " (" + - COLUMN_NAME_ID + " INTEGER PRIMARY KEY," + + + private static final String SQL_CREATE_ENTRIES = + "CREATE TABLE " + TABLE_NAME + " (" + + COLUMN_NAME_ID + " INTEGER PRIMARY KEY," + COLUMN_NAME_USER_ID + " INTEGER," + - COLUMN_NAME_DATE_TIME + " TEXT," + - COLUMN_NAME_WEIGHT + " REAL," + - COLUMN_NAME_FAT + " REAL," + - COLUMN_NAME_WATER + " REAL," + - COLUMN_NAME_MUSCLE + " REAL," + + COLUMN_NAME_DATE_TIME + " TEXT," + + COLUMN_NAME_WEIGHT + " REAL," + + COLUMN_NAME_FAT + " REAL," + + COLUMN_NAME_WATER + " REAL," + + COLUMN_NAME_MUSCLE + " REAL," + COLUMN_NAME_LBW + " REAL," + COLUMN_NAME_BONE + " REAL," + COLUMN_NAME_WAIST + " REAL," + COLUMN_NAME_HIP + " REAL," + COLUMN_NAME_COMMENT + " TEXT," + COLUMN_NAME_ENABLE + " INTEGER" + - ")"; + ")"; private static final String SQL_DELETE_ENTRIES = - "DROP TABLE IF EXISTS " + TABLE_NAME; + "DROP TABLE IF EXISTS " + TABLE_NAME; private static String[] projection = { @@ -93,17 +93,17 @@ public class ScaleDatabase extends SQLiteOpenHelper { private SimpleDateFormat formatDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US); - public ScaleDatabase(Context context) { + public ScaleDatabase(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); - } + } - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(SQL_CREATE_ENTRIES); - } + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(SQL_CREATE_ENTRIES); + } - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion == 1 && newVersion == 2) { db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_NAME_COMMENT + " TEXT DEFAULT ''"); } @@ -124,14 +124,14 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion == 5 && newVersion == 6) { db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_NAME_LBW + " REAL DEFAULT 0"); } - } - - public void clearScaleData(int userId) { + } + + public void clearScaleData(int userId) { dbWrite.delete(TABLE_NAME, COLUMN_NAME_USER_ID + "=" + Integer.toString(userId), null); - } + } - public boolean insertEntry(ScaleData scaleData) { - SQLiteDatabase db = getWritableDatabase(); + public boolean insertEntry(ScaleData scaleData) { + SQLiteDatabase db = getWritableDatabase(); Cursor cursorScaleDB = db.query(TABLE_NAME, new String[] {COLUMN_NAME_DATE_TIME}, COLUMN_NAME_DATE_TIME + "=? AND " + COLUMN_NAME_USER_ID + "=?", new String[] {formatDateTime.format(scaleData.getDateTime()), Integer.toString(scaleData.getUserId())}, null, null, null); @@ -170,7 +170,7 @@ public boolean insertEntry(ScaleData scaleData) { cursorScaleDB.close(); return true; - } + } public void updateEntry(long id, ScaleData scaleData) { ContentValues values = new ContentValues(); @@ -198,13 +198,13 @@ public ScaleData[] getTupleDataEntry(int userId, long id) // selected scale data entry cursorScaleDB = dbRead.query( - TABLE_NAME, // The table to query - projection, // The columns to return - COLUMN_NAME_USER_ID + "=? AND " + COLUMN_NAME_ID + "=?", // The columns for the WHERE clause - new String[] {Integer.toString(userId), Long.toString(id)}, // The values for the WHERE clause - null, // don't group the rows - null, // don't filter by row groups - null, // The sort order + TABLE_NAME, // The table to query + projection, // The columns to return + COLUMN_NAME_USER_ID + "=? AND " + COLUMN_NAME_ID + "=?", // The columns for the WHERE clause + new String[] {Integer.toString(userId), Long.toString(id)}, // The values for the WHERE clause + null, // don't group the rows + null, // don't filter by row groups + null, // The sort order "1" // Limit ); @@ -217,13 +217,13 @@ public ScaleData[] getTupleDataEntry(int userId, long id) // previous scale entry cursorScaleDB = dbRead.query( - TABLE_NAME, // The table to query - projection, // The columns to return - COLUMN_NAME_USER_ID + "=? AND " + COLUMN_NAME_DATE_TIME + "? AND " + COLUMN_NAME_ENABLE + "=1", // The columns for the WHERE clause - new String[] {Integer.toString(userId), formatDateTime.format(tupleScaleData[1].getDateTime())}, // The values for the WHERE clause - null, // don't group the rows - null, // don't filter by row groups + TABLE_NAME, // The table to query + projection, // The columns to return + COLUMN_NAME_USER_ID + "=? AND " + COLUMN_NAME_DATE_TIME + ">? AND " + COLUMN_NAME_ENABLE + "=1", // The columns for the WHERE clause + new String[] {Integer.toString(userId), formatDateTime.format(tupleScaleData[1].getDateTime())}, // The values for the WHERE clause + null, // don't group the rows + null, // don't filter by row groups COLUMN_NAME_DATE_TIME, // The sort order "1" // Limit ); @@ -311,13 +311,13 @@ public ArrayList getScaleDataOfMonth(int userId, int year, int month) end_cal.add(Calendar.MONTH, 1); Cursor cursorScaleDB = dbRead.query( - TABLE_NAME, // The table to query - projection, // The columns to return + TABLE_NAME, // The table to query + projection, // The columns to return COLUMN_NAME_DATE_TIME + " >= ? AND " + COLUMN_NAME_DATE_TIME + " < ? AND " + COLUMN_NAME_USER_ID + "=? AND " + COLUMN_NAME_ENABLE + "=1", // The columns for the WHERE clause new String[]{formatDateTime.format(start_cal.getTime()), formatDateTime.format(end_cal.getTime()), Integer.toString(userId)}, // The values for the WHERE clause - null, // don't group the rows - null, // don't filter by row groups - sortOrder // The sort order + null, // don't group the rows + null, // don't filter by row groups + sortOrder // The sort order ); cursorScaleDB.moveToFirst(); @@ -345,13 +345,13 @@ public ArrayList getScaleDataOfYear(int userId, int year) { end_cal.set(year+1, Calendar.JANUARY, 1, 0, 0, 0); Cursor cursorScaleDB = dbRead.query( - TABLE_NAME, // The table to query - projection, // The columns to return + TABLE_NAME, // The table to query + projection, // The columns to return COLUMN_NAME_DATE_TIME + " >= ? AND " + COLUMN_NAME_DATE_TIME + " < ? AND " + COLUMN_NAME_USER_ID + "=? AND " + COLUMN_NAME_ENABLE + "=1", // The columns for the WHERE clause new String[]{formatDateTime.format(start_cal.getTime()), formatDateTime.format(end_cal.getTime()), Integer.toString(userId)}, // The values for the WHERE clause - null, // don't group the rows - null, // don't filter by row groups - sortOrder // The sort order + null, // don't group the rows + null, // don't filter by row groups + sortOrder // The sort order ); cursorScaleDB.moveToFirst(); @@ -367,8 +367,8 @@ public ArrayList getScaleDataOfYear(int userId, int year) { return scaleDataList; } - public ArrayList getScaleDataList(int userId) { - ArrayList scaleDataList = new ArrayList(); + public ArrayList getScaleDataList(int userId) { + ArrayList scaleDataList = new ArrayList(); try { String sortOrder = COLUMN_NAME_DATE_TIME + " DESC"; @@ -395,9 +395,9 @@ public ArrayList getScaleDataList(int userId) { } catch (SQLException ex) { Log.e("ScaleDatabase", "SQL exception occured while getting scale data list: " + ex.getMessage()); } - - return scaleDataList; - } + + return scaleDataList; + } private ScaleData readAtCursor (Cursor cur) { @@ -421,7 +421,7 @@ private ScaleData readAtCursor (Cursor cur) { } catch (ParseException ex) { Log.e("ScaleDatabase", "Can't parse the date time string: " + ex.getMessage()); } - catch ( IllegalArgumentException ex) { + catch (IllegalArgumentException ex) { Log.e("ScaleDatabase", "Illegal argument while reading from scale database: " + ex.getMessage()); } diff --git a/android_app/app/src/main/java/com/health/openscale/core/database/ScaleUserDatabase.java b/android_app/app/src/main/java/com/health/openscale/core/database/ScaleUserDatabase.java index 4131a399b..4d0d79e6d 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/database/ScaleUserDatabase.java +++ b/android_app/app/src/main/java/com/health/openscale/core/database/ScaleUserDatabase.java @@ -47,8 +47,8 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { private static final String COLUMN_NAME_GOAL_DATE = "goal_date"; private static final String SQL_CREATE_ENTRIES = - "CREATE TABLE " + TABLE_NAME + " (" + - COLUMN_NAME_ID + " INTEGER PRIMARY KEY," + + "CREATE TABLE " + TABLE_NAME + " (" + + COLUMN_NAME_ID + " INTEGER PRIMARY KEY," + COLUMN_NAME_USER_NAME + " TEXT," + COLUMN_NAME_BIRTHDAY + " TEXT," + COLUMN_NAME_BODY_HEIGHT + " INTEGER," + @@ -57,10 +57,10 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { COLUMN_NAME_INITIAL_WEIGHT + " REAL," + COLUMN_NAME_GOAL_WEIGHT + " REAL," + COLUMN_NAME_GOAL_DATE + " TEXT" + - ")"; + ")"; private static final String SQL_DELETE_ENTRIES = - "DROP TABLE IF EXISTS " + TABLE_NAME; + "DROP TABLE IF EXISTS " + TABLE_NAME; private static String[] projection = { COLUMN_NAME_ID, @@ -76,17 +76,17 @@ public class ScaleUserDatabase extends SQLiteOpenHelper { private SimpleDateFormat formatDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US); - public ScaleUserDatabase(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } + public ScaleUserDatabase(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(SQL_CREATE_ENTRIES); - } + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(SQL_CREATE_ENTRIES); + } - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion == 1 && newVersion == 2) { db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_NAME_GENDER + " INTEGER DEFAULT 0"); db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_NAME_GOAL_WEIGHT + " REAL DEFAULT 0"); @@ -96,16 +96,16 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion == 2 && newVersion == 3) { db.execSQL("ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + COLUMN_NAME_INITIAL_WEIGHT + " REAL DEFAULT 0"); } - } - - public void clearDatabase() { - SQLiteDatabase db = getWritableDatabase(); - - db.delete(TABLE_NAME, null, null); - } + } + + public void clearDatabase() { + SQLiteDatabase db = getWritableDatabase(); + + db.delete(TABLE_NAME, null, null); + } - public boolean insertEntry(ScaleUser scaleUser) { - SQLiteDatabase db = getWritableDatabase(); + public boolean insertEntry(ScaleUser scaleUser) { + SQLiteDatabase db = getWritableDatabase(); ContentValues values = new ContentValues(); values.put(COLUMN_NAME_USER_NAME, scaleUser.user_name); @@ -128,7 +128,7 @@ public boolean insertEntry(ScaleUser scaleUser) { } return true; - } + } public void deleteEntry(int id) { SQLiteDatabase db = getWritableDatabase(); @@ -158,13 +158,13 @@ public ScaleUser getScaleUser(int id) SQLiteDatabase db = getReadableDatabase(); Cursor cursorScaleDB = db.query( - TABLE_NAME, // The table to query - projection, // The columns to return - COLUMN_NAME_ID + "=?", // The columns for the WHERE clause - new String[] {Integer.toString(id)}, // The values for the WHERE clause - null, // don't group the rows - null, // don't filter by row groups - null // The sort order + TABLE_NAME, // The table to query + projection, // The columns to return + COLUMN_NAME_ID + "=?", // The columns for the WHERE clause + new String[] {Integer.toString(id)}, // The values for the WHERE clause + null, // don't group the rows + null, // don't filter by row groups + null // The sort order ); cursorScaleDB.moveToFirst(); @@ -176,34 +176,34 @@ public ScaleUser getScaleUser(int id) return scaleUser; } - public ArrayList getScaleUserList() { - SQLiteDatabase db = getReadableDatabase(); - ArrayList scaleUserDBEntries = new ArrayList(); - - String sortOrder = COLUMN_NAME_ID + " ASC"; - - Cursor cursorScaleDB = db.query( - TABLE_NAME, // The table to query - projection, // The columns to return - null, // The columns for the WHERE clause - null, // The values for the WHERE clause - null, // don't group the rows - null, // don't filter by row groups - sortOrder // The sort order - ); + public ArrayList getScaleUserList() { + SQLiteDatabase db = getReadableDatabase(); + ArrayList scaleUserDBEntries = new ArrayList(); - cursorScaleDB.moveToFirst(); + String sortOrder = COLUMN_NAME_ID + " ASC"; - while (!cursorScaleDB.isAfterLast()) { + Cursor cursorScaleDB = db.query( + TABLE_NAME, // The table to query + projection, // The columns to return + null, // The columns for the WHERE clause + null, // The values for the WHERE clause + null, // don't group the rows + null, // don't filter by row groups + sortOrder // The sort order + ); + + cursorScaleDB.moveToFirst(); + + while (!cursorScaleDB.isAfterLast()) { scaleUserDBEntries.add(readAtCursor(cursorScaleDB)); - - cursorScaleDB.moveToNext(); - } + + cursorScaleDB.moveToNext(); + } cursorScaleDB.close(); - - return scaleUserDBEntries; - } + + return scaleUserDBEntries; + } private ScaleUser readAtCursor (Cursor cur) { ScaleUser scaleUser = new ScaleUser(); @@ -227,7 +227,7 @@ private ScaleUser readAtCursor (Cursor cur) { } catch (ParseException ex) { Log.e("ScaleDatabase", "Can't parse the date time string: " + ex.getMessage()); } - catch ( IllegalArgumentException ex) { + catch (IllegalArgumentException ex) { Log.e("ScaleDatabase", "Illegal argument while reading from scale database: " + ex.getMessage()); } diff --git a/android_app/app/src/main/java/com/health/openscale/core/datatypes/ScaleData.java b/android_app/app/src/main/java/com/health/openscale/core/datatypes/ScaleData.java index bcc3296fe..2f7d0a0c3 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/datatypes/ScaleData.java +++ b/android_app/app/src/main/java/com/health/openscale/core/datatypes/ScaleData.java @@ -194,7 +194,7 @@ public float getBMR(ScaleUser scaleUser) { } public float getWHtR(int body_height) { - return waist / (float)body_height ; + return waist / (float)body_height; } public float getWHR() { @@ -205,9 +205,9 @@ public float getWHR() { return waist / hip; } - @Override - public String toString() - { - return "ID : " + id + " USER_ID: " + user_id + " DATE_TIME: " + date_time.toString() + " WEIGHT: " + weight + " FAT: " + fat + " WATER: " + water + " MUSCLE: " + muscle + " LBW: " + lbw + " WAIST: " + waist + " HIP: " + hip + " BONE: " + bone + " COMMENT: " + comment; - } + @Override + public String toString() + { + return "ID : " + id + " USER_ID: " + user_id + " DATE_TIME: " + date_time.toString() + " WEIGHT: " + weight + " FAT: " + fat + " WATER: " + water + " MUSCLE: " + muscle + " LBW: " + lbw + " WAIST: " + waist + " HIP: " + hip + " BONE: " + bone + " COMMENT: " + comment; + } } diff --git a/android_app/app/src/main/java/com/health/openscale/core/datatypes/ScaleUser.java b/android_app/app/src/main/java/com/health/openscale/core/datatypes/ScaleUser.java index a21ab20aa..8cc1ad3b2 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/datatypes/ScaleUser.java +++ b/android_app/app/src/main/java/com/health/openscale/core/datatypes/ScaleUser.java @@ -24,11 +24,11 @@ public class ScaleUser { private static float KG_LB = 2.20462f; private static float KG_ST = 0.157473f; - public int id; + public int id; public String user_name; - public Date birthday; - public int body_height; - public int scale_unit; + public Date birthday; + public int body_height; + public int scale_unit; public int gender; private float initial_weight; public float goal_weight; @@ -106,9 +106,9 @@ public float getConvertedInitialWeight() { return converted_weight; } - @Override - public String toString() - { - return "ID : " + id + " NAME: " + user_name + " BIRTHDAY: " + birthday.toString() + " BODY_HEIGHT: " + body_height + " SCALE_UNIT: " + UNIT_STRING[scale_unit] + " GENDER " + gender + " INITIAL WEIGHT " + initial_weight + " GOAL WEIGHT " + goal_weight + " GOAL DATE " + goal_date.toString(); - } + @Override + public String toString() + { + return "ID : " + id + " NAME: " + user_name + " BIRTHDAY: " + birthday.toString() + " BODY_HEIGHT: " + body_height + " SCALE_UNIT: " + UNIT_STRING[scale_unit] + " GENDER " + gender + " INITIAL WEIGHT " + initial_weight + " GOAL WEIGHT " + goal_weight + " GOAL DATE " + goal_date.toString(); + } } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java index 39feed8b6..999d1e38b 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java @@ -53,69 +53,69 @@ public class MainActivity extends ActionBarActivity implements - ActionBar.TabListener { - - /** - * The {@link android.support.v4.view.PagerAdapter} that will provide - * fragments for each of the sections. We use a {@link FragmentPagerAdapter} - * derivative, which will keep every loaded fragment in memory. If this - * becomes too memory intensive, it may be best to switch to a - * {@link android.support.v4.app.FragmentStatePagerAdapter}. - */ - private SectionsPagerAdapter mSectionsPagerAdapter; - - private static boolean firstAppStart = true; - private static int bluetoothStatusIcon = R.drawable.ic_bluetooth_disabled; - private static MenuItem bluetoothStatus; - - /** - * The {@link ViewPager} that will host the section contents. - */ - private ViewPager mViewPager; - - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.activity_main); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - // Set up the action bar. - final ActionBar actionBar = getSupportActionBar(); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + ActionBar.TabListener { + + /** + * The {@link android.support.v4.view.PagerAdapter} that will provide + * fragments for each of the sections. We use a {@link FragmentPagerAdapter} + * derivative, which will keep every loaded fragment in memory. If this + * becomes too memory intensive, it may be best to switch to a + * {@link android.support.v4.app.FragmentStatePagerAdapter}. + */ + private SectionsPagerAdapter mSectionsPagerAdapter; + + private static boolean firstAppStart = true; + private static int bluetoothStatusIcon = R.drawable.ic_bluetooth_disabled; + private static MenuItem bluetoothStatus; + + /** + * The {@link ViewPager} that will host the section contents. + */ + private ViewPager mViewPager; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + // Set up the action bar. + final ActionBar actionBar = getSupportActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); actionBar.setLogo(R.drawable.ic_launcher_openscale); - // Create the adapter that will return a fragment for each of the three - // primary sections of the activity. - mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); - - // Set up the ViewPager with the sections adapter. - mViewPager = (ViewPager) findViewById(R.id.pager); - mViewPager.setAdapter(mSectionsPagerAdapter); - - // When swiping between different sections, select the corresponding - // tab. We can also use ActionBar.Tab#select() to do this if we have - // a reference to the Tab. - mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { - @Override - public void onPageSelected(int position) { - actionBar.setSelectedNavigationItem(position); - } - }); - - // For each of the sections in the app, add a tab to the action bar. - for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) { - // Create a tab with text corresponding to the page title defined by - // the adapter. Also specify this Activity object, which implements - // the TabListener interface, as the callback (listener) for when - // this tab is selected. - actionBar.addTab(actionBar.newTab() - .setText(mSectionsPagerAdapter.getPageTitle(i)) - .setTabListener(this)); - } + // Create the adapter that will return a fragment for each of the three + // primary sections of the activity. + mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); + + // Set up the ViewPager with the sections adapter. + mViewPager = (ViewPager) findViewById(R.id.pager); + mViewPager.setAdapter(mSectionsPagerAdapter); + + // When swiping between different sections, select the corresponding + // tab. We can also use ActionBar.Tab#select() to do this if we have + // a reference to the Tab. + mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + actionBar.setSelectedNavigationItem(position); + } + }); + + // For each of the sections in the app, add a tab to the action bar. + for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) { + // Create a tab with text corresponding to the page title defined by + // the adapter. Also specify this Activity object, which implements + // the TabListener interface, as the callback (listener) for when + // this tab is selected. + actionBar.addTab(actionBar.newTab() + .setText(mSectionsPagerAdapter.getPageTitle(i)) + .setTabListener(this)); + } if (prefs.getBoolean("firstStart", true)) { @@ -125,210 +125,210 @@ public void onPageSelected(int position) { prefs.edit().putBoolean("firstStart", false).commit(); } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.main, menu); - - bluetoothStatus = menu.findItem(R.id.action_bluetooth_status); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - // Just search for a bluetooth device just once at the start of the app and if start preference enabled - if (firstAppStart && prefs.getBoolean("btEnable", false)) { - invokeSearchBluetoothDevice(); - firstAppStart = false; - } else { - // Set current bluetooth status icon while e.g. orientation changes - setBluetoothStatusIcon(bluetoothStatusIcon); - } - - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - - if (id == R.id.action_general_settings) { - Intent intent = new Intent(this, SettingsActivity.class); - startActivityForResult(intent, 1); - return true; - } - - if (id == R.id.action_bluetooth_status) { - invokeSearchBluetoothDevice(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - private void invokeSearchBluetoothDevice() { - final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); - BluetoothAdapter btAdapter = bluetoothManager.getAdapter(); - - if (btAdapter == null || !btAdapter.isEnabled()) { - setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled); - Toast.makeText(getApplicationContext(), "Bluetooth " + getResources().getString(R.string.info_is_not_enable), Toast.LENGTH_SHORT).show(); - - Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); - startActivityForResult(enableBtIntent, 1); - return; - } - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - String deviceName = prefs.getString("btDeviceName", "MI_SCALE"); - - // Check if Bluetooth 4.x is available - if (deviceName != "openScale_MCU") { - if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { - setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled); - Toast.makeText(getApplicationContext(), "Bluetooth 4.x " + getResources().getString(R.string.info_is_not_available), Toast.LENGTH_SHORT).show(); - return; - } - } - - Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_try_connection) + " " + deviceName, Toast.LENGTH_SHORT).show(); - setBluetoothStatusIcon(R.drawable.ic_bluetooth_searching); - - OpenScale.getInstance(getApplicationContext()).stopSearchingForBluetooth(); - if (!OpenScale.getInstance(getApplicationContext()).startSearchingForBluetooth(deviceName, callbackBtHandler)) { - Toast.makeText(getApplicationContext(), deviceName + " " + getResources().getString(R.string.label_bt_device_no_support), Toast.LENGTH_SHORT).show(); - } - } - - private final Handler callbackBtHandler = new Handler() { - @Override - public void handleMessage(Message msg) { + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + + bluetoothStatus = menu.findItem(R.id.action_bluetooth_status); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + // Just search for a bluetooth device just once at the start of the app and if start preference enabled + if (firstAppStart && prefs.getBoolean("btEnable", false)) { + invokeSearchBluetoothDevice(); + firstAppStart = false; + } else { + // Set current bluetooth status icon while e.g. orientation changes + setBluetoothStatusIcon(bluetoothStatusIcon); + } + + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + if (id == R.id.action_general_settings) { + Intent intent = new Intent(this, SettingsActivity.class); + startActivityForResult(intent, 1); + return true; + } + + if (id == R.id.action_bluetooth_status) { + invokeSearchBluetoothDevice(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + private void invokeSearchBluetoothDevice() { + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + BluetoothAdapter btAdapter = bluetoothManager.getAdapter(); + + if (btAdapter == null || !btAdapter.isEnabled()) { + setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled); + Toast.makeText(getApplicationContext(), "Bluetooth " + getResources().getString(R.string.info_is_not_enable), Toast.LENGTH_SHORT).show(); + + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, 1); + return; + } + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + String deviceName = prefs.getString("btDeviceName", "MI_SCALE"); + + // Check if Bluetooth 4.x is available + if (deviceName != "openScale_MCU") { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + setBluetoothStatusIcon(R.drawable.ic_bluetooth_disabled); + Toast.makeText(getApplicationContext(), "Bluetooth 4.x " + getResources().getString(R.string.info_is_not_available), Toast.LENGTH_SHORT).show(); + return; + } + } + + Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_try_connection) + " " + deviceName, Toast.LENGTH_SHORT).show(); + setBluetoothStatusIcon(R.drawable.ic_bluetooth_searching); + + OpenScale.getInstance(getApplicationContext()).stopSearchingForBluetooth(); + if (!OpenScale.getInstance(getApplicationContext()).startSearchingForBluetooth(deviceName, callbackBtHandler)) { + Toast.makeText(getApplicationContext(), deviceName + " " + getResources().getString(R.string.label_bt_device_no_support), Toast.LENGTH_SHORT).show(); + } + } + + private final Handler callbackBtHandler = new Handler() { + @Override + public void handleMessage(Message msg) { BluetoothCommunication.BT_STATUS_CODE btStatusCode = BluetoothCommunication.BT_STATUS_CODE.values()[msg.what]; - switch (btStatusCode) { - case BT_RETRIEVE_SCALE_DATA: - setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_success); - ScaleData scaleBtData = (ScaleData) msg.obj; - - scaleBtData.setConvertedWeight(scaleBtData.getWeight(), OpenScale.getInstance(getApplicationContext()).getSelectedScaleUser().scale_unit); - - OpenScale.getInstance(getApplicationContext()).addScaleData(scaleBtData); - break; - case BT_INIT_PROCESS: - setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_success); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_init), Toast.LENGTH_SHORT).show(); - Log.d("OpenScale", "Bluetooth initializing"); - break; - case BT_CONNECTION_LOST: - setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_lost); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_connection_lost), Toast.LENGTH_SHORT).show(); - Log.d("OpenScale", "Bluetooth connection lost"); - break; - case BT_NO_DEVICE_FOUND: - setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_lost); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_no_device), Toast.LENGTH_SHORT).show(); - Log.d("OpenScale", "No Bluetooth device found"); - break; - case BT_CONNECTION_ESTABLISHED: - setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_success); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_connection_successful), Toast.LENGTH_SHORT).show(); - Log.d("OpenScale", "Bluetooth connection successful established"); - break; - case BT_UNEXPECTED_ERROR: - setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_lost); - Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_connection_error) + ": " + msg.obj, Toast.LENGTH_SHORT).show(); - Log.e("OpenScale", "Bluetooth unexpected error: " + msg.obj); - break; - case BT_SCALE_MESSAGE: - String toastMessage = String.format(getResources().getString(msg.arg1), msg.obj); - Toast.makeText(getApplicationContext(), toastMessage, Toast.LENGTH_LONG).show(); - break; - } - } - }; - - private void setBluetoothStatusIcon(int iconRessource) { - bluetoothStatusIcon = iconRessource; - bluetoothStatus.setIcon(getResources().getDrawable(bluetoothStatusIcon)); - } - - @Override - public void onTabSelected(ActionBar.Tab tab, - FragmentTransaction fragmentTransaction) { - // When the given tab is selected, switch to the corresponding page in - // the ViewPager. - mViewPager.setCurrentItem(tab.getPosition()); - } - - @Override - public void onTabUnselected(ActionBar.Tab tab, - FragmentTransaction fragmentTransaction) { - } - - @Override - public void onTabReselected(ActionBar.Tab tab, - FragmentTransaction fragmentTransaction) { - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - - if (requestCode == 1) { - mSectionsPagerAdapter.notifyDataSetChanged(); - } - } - - /** - * A {@link FragmentPagerAdapter} that returns a fragment corresponding to - * one of the sections/tabs/pages. - */ - public class SectionsPagerAdapter extends FragmentPagerAdapter { - - private OverviewFragment overviewFrag; - private GraphFragment graphFrag; - private TableFragment tableFrag; - private StatisticsFragment statisticsFrag; - - public SectionsPagerAdapter(FragmentManager fm) { - super(fm); - - overviewFrag = new OverviewFragment(); - graphFrag = new GraphFragment(); - tableFrag = new TableFragment(); - statisticsFrag = new StatisticsFragment(); - } - - @Override - public Fragment getItem(int position) { - // getItem is called to instantiate the fragment for the given page. - // Return a PlaceholderFragment (defined as a static inner class - // below). - - switch (position) { - case 0: - return overviewFrag; - case 1: - return graphFrag; - case 2: - return tableFrag; - case 3: - return statisticsFrag; - } - - return null; - } - - @Override - public int getCount() { - return 4; - } - - @Override - public CharSequence getPageTitle(int position) { - Locale l = Locale.getDefault(); - switch (position) { + switch (btStatusCode) { + case BT_RETRIEVE_SCALE_DATA: + setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_success); + ScaleData scaleBtData = (ScaleData) msg.obj; + + scaleBtData.setConvertedWeight(scaleBtData.getWeight(), OpenScale.getInstance(getApplicationContext()).getSelectedScaleUser().scale_unit); + + OpenScale.getInstance(getApplicationContext()).addScaleData(scaleBtData); + break; + case BT_INIT_PROCESS: + setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_success); + Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_init), Toast.LENGTH_SHORT).show(); + Log.d("OpenScale", "Bluetooth initializing"); + break; + case BT_CONNECTION_LOST: + setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_lost); + Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_connection_lost), Toast.LENGTH_SHORT).show(); + Log.d("OpenScale", "Bluetooth connection lost"); + break; + case BT_NO_DEVICE_FOUND: + setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_lost); + Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_no_device), Toast.LENGTH_SHORT).show(); + Log.d("OpenScale", "No Bluetooth device found"); + break; + case BT_CONNECTION_ESTABLISHED: + setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_success); + Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_connection_successful), Toast.LENGTH_SHORT).show(); + Log.d("OpenScale", "Bluetooth connection successful established"); + break; + case BT_UNEXPECTED_ERROR: + setBluetoothStatusIcon(R.drawable.ic_bluetooth_connection_lost); + Toast.makeText(getApplicationContext(), getResources().getString(R.string.info_bluetooth_connection_error) + ": " + msg.obj, Toast.LENGTH_SHORT).show(); + Log.e("OpenScale", "Bluetooth unexpected error: " + msg.obj); + break; + case BT_SCALE_MESSAGE: + String toastMessage = String.format(getResources().getString(msg.arg1), msg.obj); + Toast.makeText(getApplicationContext(), toastMessage, Toast.LENGTH_LONG).show(); + break; + } + } + }; + + private void setBluetoothStatusIcon(int iconRessource) { + bluetoothStatusIcon = iconRessource; + bluetoothStatus.setIcon(getResources().getDrawable(bluetoothStatusIcon)); + } + + @Override + public void onTabSelected(ActionBar.Tab tab, + FragmentTransaction fragmentTransaction) { + // When the given tab is selected, switch to the corresponding page in + // the ViewPager. + mViewPager.setCurrentItem(tab.getPosition()); + } + + @Override + public void onTabUnselected(ActionBar.Tab tab, + FragmentTransaction fragmentTransaction) { + } + + @Override + public void onTabReselected(ActionBar.Tab tab, + FragmentTransaction fragmentTransaction) { + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + + if (requestCode == 1) { + mSectionsPagerAdapter.notifyDataSetChanged(); + } + } + + /** + * A {@link FragmentPagerAdapter} that returns a fragment corresponding to + * one of the sections/tabs/pages. + */ + public class SectionsPagerAdapter extends FragmentPagerAdapter { + + private OverviewFragment overviewFrag; + private GraphFragment graphFrag; + private TableFragment tableFrag; + private StatisticsFragment statisticsFrag; + + public SectionsPagerAdapter(FragmentManager fm) { + super(fm); + + overviewFrag = new OverviewFragment(); + graphFrag = new GraphFragment(); + tableFrag = new TableFragment(); + statisticsFrag = new StatisticsFragment(); + } + + @Override + public Fragment getItem(int position) { + // getItem is called to instantiate the fragment for the given page. + // Return a PlaceholderFragment (defined as a static inner class + // below). + + switch (position) { + case 0: + return overviewFrag; + case 1: + return graphFrag; + case 2: + return tableFrag; + case 3: + return statisticsFrag; + } + + return null; + } + + @Override + public int getCount() { + return 4; + } + + @Override + public CharSequence getPageTitle(int position) { + Locale l = Locale.getDefault(); + switch (position) { case 0: return getString(R.string.title_overview).toUpperCase(l); case 1: @@ -337,23 +337,23 @@ public CharSequence getPageTitle(int position) { return getString(R.string.title_table).toUpperCase(l); case 3: return getString(R.string.title_statistics).toUpperCase(l); - } - return null; - } + } + return null; + } - @Override - public int getItemPosition(Object object) { - return POSITION_NONE; - } + @Override + public int getItemPosition(Object object) { + return POSITION_NONE; + } - @Override + @Override public void notifyDataSetChanged() { - super.notifyDataSetChanged(); + super.notifyDataSetChanged(); tableFrag = new TableFragment(); graphFrag = new GraphFragment(); overviewFrag = new OverviewFragment(); statisticsFrag = new StatisticsFragment(); } - } + } } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/activities/DataEntryActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/activities/DataEntryActivity.java index 314c24f3e..d4a1bb47f 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/activities/DataEntryActivity.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/activities/DataEntryActivity.java @@ -44,6 +44,7 @@ import com.health.openscale.gui.views.HipMeasurementView; import com.health.openscale.gui.views.LBWMeasurementView; import com.health.openscale.gui.views.MeasurementView; +import com.health.openscale.gui.views.MeasurementViewUpdateListener; import com.health.openscale.gui.views.MuscleMeasurementView; import com.health.openscale.gui.views.TimeMeasurementView; import com.health.openscale.gui.views.WHRMeasurementView; @@ -92,15 +93,15 @@ public class DataEntryActivity extends Activity { private long id; - private Context context; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + private Context context; - setContentView(R.layout.activity_dataentry); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - context = this; + setContentView(R.layout.activity_dataentry); + + context = this; tableLayoutDataEntry = (TableLayout) findViewById(R.id.tableLayoutDataEntry); @@ -145,8 +146,8 @@ protected void onCreate(Bundle savedInstanceState) { txtDataNr = (TextView) findViewById(R.id.txtDataNr); - btnAdd = (Button) findViewById(R.id.btnAdd); - btnOk = (Button) findViewById(R.id.btnOk); + btnAdd = (Button) findViewById(R.id.btnAdd); + btnOk = (Button) findViewById(R.id.btnOk); btnCancel = (Button) findViewById(R.id.btnCancel); btnLeft = (Button) findViewById(R.id.btnLeft); btnRight = (Button) findViewById(R.id.btnRight); @@ -164,7 +165,7 @@ protected void onCreate(Bundle savedInstanceState) { expandButton.setOnClickListener(new onClickListenerToggleButton()); updateOnView(); - } + } private void updateOnView() @@ -172,6 +173,7 @@ private void updateOnView() SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); for (MeasurementView measurement : dataEntryMeasurements) { + measurement.setOnUpdateListener(null); measurement.updatePreferences(prefs); } @@ -189,7 +191,8 @@ private void updateOnView() switchEditMode.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#D3D3D3"))); } - if (prefs.getBoolean(String.valueOf(expandButton.getId()), false)) { + final boolean doExpand = prefs.getBoolean(String.valueOf(expandButton.getId()), false); + if (doExpand) { expandButton.setBackgroundTintList(ColorStateList.valueOf(ChartUtils.COLOR_ORANGE)); } else { expandButton.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#D3D3D3"))); @@ -211,32 +214,32 @@ private void updateOnView() for (MeasurementView measurement : dataEntryMeasurements) { measurement.updateValue(selectedScaleData); measurement.updateDiff(selectedScaleData, prevScaleData); - measurement.setExpand(prefs.getBoolean(String.valueOf(expandButton.getId()), false)); + measurement.setExpand(doExpand); } - - return; - } - - - if (!OpenScale.getInstance(getApplicationContext()).getScaleDataList().isEmpty()) - { + } else if (!OpenScale.getInstance(getApplicationContext()).getScaleDataList().isEmpty()) { setViewMode(MeasurementView.MeasurementViewMode.ADD); txtDataNr.setText(DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT).format(new Date())); ScaleData lastScaleData = OpenScale.getInstance(getApplicationContext()).getScaleDataList().get(0); // show as default last scale data + lastScaleData.setDateTime(new Date()); + lastScaleData.setComment(""); for (MeasurementView measurement : dataEntryMeasurements) { - lastScaleData.setDateTime(new Date()); - lastScaleData.setComment(""); measurement.updateValue(lastScaleData); } } else { setViewMode(MeasurementView.MeasurementViewMode.ADD); // show default values + ScaleData newScaleData = new ScaleData(); for (MeasurementView measurement : dataEntryMeasurements) { - measurement.updateValue(new ScaleData()); + measurement.updateValue(newScaleData); } } + + onMeasurementViewUpdateListener updateListener = new onMeasurementViewUpdateListener(); + for (MeasurementView measurement : dataEntryMeasurements) { + measurement.setOnUpdateListener(updateListener); + } } private void setViewMode(MeasurementView.MeasurementViewMode viewMode) @@ -350,6 +353,30 @@ private boolean moveRight() return false; } + private class onMeasurementViewUpdateListener implements MeasurementViewUpdateListener { + @Override + public void onMeasurementViewUpdate(MeasurementView view) { + ArrayList viewsToUpdate = new ArrayList<>(); + if (view == weightMeasurement) { + viewsToUpdate.add(bmiMeasurementView); + viewsToUpdate.add(bmrMeasurementView); + } else if (view == waistMeasurement) { + viewsToUpdate.add(wHtRMeasurementView); + viewsToUpdate.add(whrMeasurementView); + } else if (view == hipMeasurement) { + viewsToUpdate.add(whrMeasurementView); + } else if (view == dateMeasurement) { + viewsToUpdate.add(bmrMeasurementView); + } + + if (!viewsToUpdate.isEmpty()) { + ScaleData scaleData = createScaleDataFromMeasurement(); + for (MeasurementView measurement : viewsToUpdate) { + measurement.updateValue(scaleData); + } + } + } + } private class onClickListenerAdd implements View.OnClickListener { @Override diff --git a/android_app/app/src/main/java/com/health/openscale/gui/activities/UserSettingsActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/activities/UserSettingsActivity.java index e7cd1af42..803a0bffc 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/activities/UserSettingsActivity.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/activities/UserSettingsActivity.java @@ -45,12 +45,12 @@ public class UserSettingsActivity extends Activity { public static final int ADD_USER_REQUEST = 0; public static final int EDIT_USER_REQUEST = 1; - private Date birthday = new Date(); - private Date goal_date = new Date(); + private Date birthday = new Date(); + private Date goal_date = new Date(); - private EditText txtUserName; - private EditText txtBodyHeight; - private EditText txtBirthday; + private EditText txtUserName; + private EditText txtBodyHeight; + private EditText txtBirthday; private EditText txtInitialWeight; private EditText txtGoalWeight; private EditText txtGoalDate; @@ -61,18 +61,18 @@ public class UserSettingsActivity extends Activity { private Button btnCancel; private Button btnDelete; - private DateFormat dateFormat = DateFormat.getDateInstance(); + private DateFormat dateFormat = DateFormat.getDateInstance(); - private Context context; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_usersettings); - context = this; + private Context context; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_usersettings); + context = this; txtUserName = (EditText) findViewById(R.id.txtUserName); - txtBodyHeight = (EditText) findViewById(R.id.txtBodyHeight); + txtBodyHeight = (EditText) findViewById(R.id.txtBodyHeight); radioScaleUnit = (RadioGroup) findViewById(R.id.groupScaleUnit); radioGender = (RadioGroup) findViewById(R.id.groupGender); txtInitialWeight = (EditText) findViewById(R.id.txtInitialWeight); @@ -125,7 +125,7 @@ public void onClick(View v) { btnOk.setText(getResources().getString(R.string.label_add)); btnDelete.setVisibility(View.GONE); } - } + } private void editMode() { @@ -173,26 +173,22 @@ private boolean validateInput() { boolean validate = true; - if( txtUserName.getText().toString().length() == 0 ) - { + if (txtUserName.getText().toString().length() == 0) { txtUserName.setError(getResources().getString(R.string.error_user_name_required)); validate = false; } - if( txtBodyHeight.getText().toString().length() == 0 ) - { + if (txtBodyHeight.getText().toString().length() == 0) { txtBodyHeight.setError(getResources().getString(R.string.error_body_height_required)); validate = false; } - if( txtInitialWeight.getText().toString().length() == 0 ) - { + if (txtInitialWeight.getText().toString().length() == 0) { txtInitialWeight.setError(getResources().getString(R.string.error_initial_weight_required)); validate = false; } - if( txtGoalWeight.getText().toString().length() == 0 ) - { + if (txtGoalWeight.getText().toString().length() == 0) { txtGoalWeight.setError(getResources().getString(R.string.error_goal_weight_required)); validate = false; } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/FragmentUpdateListener.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/FragmentUpdateListener.java index 75fbd5a15..a93c8fd98 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/FragmentUpdateListener.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/FragmentUpdateListener.java @@ -21,5 +21,5 @@ import java.util.ArrayList; public interface FragmentUpdateListener { - public void updateOnView(ArrayList scaleDataList); + public void updateOnView(ArrayList scaleDataList); } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java index 627281a99..395ce2c22 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/GraphFragment.java @@ -63,9 +63,9 @@ import lecho.lib.hellocharts.view.ColumnChartView; import lecho.lib.hellocharts.view.LineChartView; -public class GraphFragment extends Fragment implements FragmentUpdateListener { - private View graphView; - private LineChartView chartBottom; +public class GraphFragment extends Fragment implements FragmentUpdateListener { + private View graphView; + private LineChartView chartBottom; private ColumnChartView chartTop; private Viewport defaultTopViewport; private TextView txtYear; @@ -88,17 +88,17 @@ public class GraphFragment extends Fragment implements FragmentUpdateListener { private ArrayList scaleDataList; private ArrayList pointIndexScaleDataList; - public GraphFragment() { + public GraphFragment() { calYears = Calendar.getInstance(); calLastSelected = Calendar.getInstance(); } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) - { - graphView = inflater.inflate(R.layout.fragment_graph, container, false); - - chartBottom = (LineChartView) graphView.findViewById(R.id.chart_bottom); + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + graphView = inflater.inflate(R.layout.fragment_graph, container, false); + + chartBottom = (LineChartView) graphView.findViewById(R.id.chart_bottom); chartTop = (ColumnChartView) graphView.findViewById(R.id.chart_top); chartBottom.setOnTouchListener(new chartBottomListener()); @@ -131,35 +131,35 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa prefs = PreferenceManager.getDefaultSharedPreferences(graphView.getContext()); - if(!prefs.getBoolean("weightEnable", true)) { + if (!prefs.getBoolean("weightEnable", true)) { diagramWeight.setVisibility(View.GONE); } - if(!prefs.getBoolean("fatEnable", true)) { + if (!prefs.getBoolean("fatEnable", true)) { diagramFat.setVisibility(View.GONE); } - if(!prefs.getBoolean("waterEnable", true)) { + if (!prefs.getBoolean("waterEnable", true)) { diagramWater.setVisibility(View.GONE); } - if(!prefs.getBoolean("muscleEnable", true)) { + if (!prefs.getBoolean("muscleEnable", true)) { diagramMuscle.setVisibility(View.GONE); } - if(!prefs.getBoolean("lbwEnable", false)) { + if (!prefs.getBoolean("lbwEnable", false)) { diagramLBW.setVisibility(View.GONE); } - if(!prefs.getBoolean("boneEnable", false)) { + if (!prefs.getBoolean("boneEnable", false)) { diagramBone.setVisibility(View.GONE); } - if(!prefs.getBoolean("waistEnable", false)) { + if (!prefs.getBoolean("waistEnable", false)) { diagramWaist.setVisibility(View.GONE); } - if(!prefs.getBoolean("hipEnable", false)) { + if (!prefs.getBoolean("hipEnable", false)) { diagramHip.setVisibility(View.GONE); } @@ -182,14 +182,14 @@ public void onClick(View view) { openScale = OpenScale.getInstance(getContext()); openScale.registerFragment(this); - return graphView; - } - - @Override - public void updateOnView(ArrayList scaleDataList) - { + return graphView; + } + + @Override + public void updateOnView(ArrayList scaleDataList) + { generateGraphs(); - } + } /** * Add a point to a point value stack. @@ -258,8 +258,7 @@ private void generateLineData(int field) pointIndexScaleDataList = new ArrayList<>(); - for(ScaleData scaleEntry: scaleDataList) - { + for (ScaleData scaleEntry: scaleDataList) { calDB.setTime(scaleEntry.getDateTime()); if (addPointValue(valuesWeight, calDB.get(field), scaleEntry.getConvertedWeight(openScale.getSelectedScaleUser().scale_unit))) { @@ -317,63 +316,63 @@ private void generateLineData(int field) setHasPoints(prefs.getBoolean("pointsEnable", true)). setFormatter(new SimpleLineChartValueFormatter(1)); - if(prefs.getBoolean("weightEnable", true) && prefs.getBoolean(String.valueOf(diagramWeight.getId()), true)) { + if (prefs.getBoolean("weightEnable", true) && prefs.getBoolean(String.valueOf(diagramWeight.getId()), true)) { lines.add(lineWeight); diagramWeight.setBackgroundTintList(ColorStateList.valueOf(ChartUtils.COLOR_VIOLET)); } else { diagramWeight.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); } - if(prefs.getBoolean("fatEnable", true) && prefs.getBoolean(String.valueOf(diagramFat.getId()), true)) { + if (prefs.getBoolean("fatEnable", true) && prefs.getBoolean(String.valueOf(diagramFat.getId()), true)) { lines.add(lineFat); diagramFat.setBackgroundTintList(ColorStateList.valueOf(ChartUtils.COLOR_ORANGE)); } else { diagramFat.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); } - if(prefs.getBoolean("waterEnable", true) && prefs.getBoolean(String.valueOf(diagramWater.getId()), true)) { + if (prefs.getBoolean("waterEnable", true) && prefs.getBoolean(String.valueOf(diagramWater.getId()), true)) { lines.add(lineWater); diagramWater.setBackgroundTintList(ColorStateList.valueOf(ChartUtils.COLOR_BLUE)); } else { diagramWater.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); } - if(prefs.getBoolean("muscleEnable", true) && prefs.getBoolean(String.valueOf(diagramMuscle.getId()), true)) { + if (prefs.getBoolean("muscleEnable", true) && prefs.getBoolean(String.valueOf(diagramMuscle.getId()), true)) { lines.add(lineMuscle); diagramMuscle.setBackgroundTintList(ColorStateList.valueOf(ChartUtils.COLOR_GREEN)); } else { diagramMuscle.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); } - if(prefs.getBoolean("lbwEnable", false) && prefs.getBoolean(String.valueOf(diagramLBW.getId()), true)) { + if (prefs.getBoolean("lbwEnable", false) && prefs.getBoolean(String.valueOf(diagramLBW.getId()), true)) { lines.add(lineLBW); diagramLBW.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#cc0099"))); } else { diagramLBW.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); } - if(prefs.getBoolean("waistEnable", false) && prefs.getBoolean(String.valueOf(diagramWaist.getId()), true)) { + if (prefs.getBoolean("waistEnable", false) && prefs.getBoolean(String.valueOf(diagramWaist.getId()), true)) { lines.add(lineWaist); diagramWaist.setBackgroundTintList(ColorStateList.valueOf(Color.MAGENTA)); } else { diagramWaist.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); } - if(prefs.getBoolean("hipEnable", false) && prefs.getBoolean(String.valueOf(diagramHip.getId()), true)) { + if (prefs.getBoolean("hipEnable", false) && prefs.getBoolean(String.valueOf(diagramHip.getId()), true)) { lines.add(lineHip); diagramHip.setBackgroundTintList(ColorStateList.valueOf(Color.YELLOW)); } else { diagramHip.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); } - if(prefs.getBoolean("boneEnable", false) && prefs.getBoolean(String.valueOf(diagramBone.getId()), true)) { + if (prefs.getBoolean("boneEnable", false) && prefs.getBoolean(String.valueOf(diagramBone.getId()), true)) { lines.add(lineBone); diagramBone.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#00cc9e"))); } else { diagramBone.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); } - if(prefs.getBoolean(String.valueOf(enableMonth.getId()), true)) { + if (prefs.getBoolean(String.valueOf(enableMonth.getId()), true)) { enableMonth.setBackgroundTintList(ColorStateList.valueOf(ChartUtils.COLOR_BLUE)); } else { enableMonth.setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#d3d3d3"))); @@ -414,7 +413,7 @@ private void generateLineData(int field) if (prefs.getBoolean("regressionLine", false)) { PolynomialFitter polyFitter = new PolynomialFitter(Integer.parseInt(prefs.getString("regressionLineOrder", "1"))); - for(PointValue weightValue : valuesWeight) { + for (PointValue weightValue : valuesWeight) { polyFitter.addPoint(weightValue.getX(), weightValue.getY()); } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/OverviewFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/OverviewFragment.java index e21c81103..6b4dc187f 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/OverviewFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/OverviewFragment.java @@ -74,6 +74,7 @@ public class OverviewFragment extends Fragment implements FragmentUpdateListener { private View overviewView; + private View userLineSeparator; private TextView txtTitleUser; private TextView txtTitleLastMeasurement; @@ -109,6 +110,7 @@ public void onCreate(Bundle savedInstanceState) { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { overviewView = inflater.inflate(R.layout.fragment_overview, container, false); + userLineSeparator = overviewView.findViewById(R.id.userLineSeparator); context = overviewView.getContext(); @@ -207,7 +209,7 @@ public void updateOnView(ArrayList scaleDataList) { private void updateUserSelection() { - currentScaleUser = OpenScale.getInstance(getContext()).getSelectedScaleUser(); + currentScaleUser = OpenScale.getInstance(getContext()).getSelectedScaleUser(); userSelectedData = null; @@ -215,19 +217,22 @@ private void updateUserSelection() { ArrayList scaleUserList = OpenScale.getInstance(getContext()).getScaleUserList(); int posUser = 0; - int pos = 0; - for(ScaleUser scaleUser :scaleUserList) { + for (ScaleUser scaleUser : scaleUserList) { spinUserAdapter.add(scaleUser.user_name); if (scaleUser.id == currentScaleUser.id) { - posUser = pos; + posUser = spinUserAdapter.getCount() - 1; } - - pos++; } spinUser.setSelection(posUser, true); + + // Hide user selector when there is only one user + int visibility = spinUserAdapter.getCount() < 2 ? View.GONE : View.VISIBLE; + txtTitleUser.setVisibility(visibility); + spinUser.setVisibility(visibility); + userLineSeparator.setVisibility(visibility); } @@ -328,35 +333,35 @@ private void updateLastLineChart(ArrayList scaleDataList) { setHasPoints(prefs.getBoolean("pointsEnable", true)). setFormatter(new SimpleLineChartValueFormatter(1)); - if(prefs.getBoolean("weightEnable", true)) { + if (prefs.getBoolean("weightEnable", true)) { lines.add(lineWeight); } - if(prefs.getBoolean("fatEnable", true)) { + if (prefs.getBoolean("fatEnable", true)) { lines.add(lineFat); } - if(prefs.getBoolean("waterEnable", true)) { + if (prefs.getBoolean("waterEnable", true)) { lines.add(lineWater); } - if(prefs.getBoolean("muscleEnable", true)) { + if (prefs.getBoolean("muscleEnable", true)) { lines.add(lineMuscle); } - if(prefs.getBoolean("lbwEnable", false)) { + if (prefs.getBoolean("lbwEnable", false)) { lines.add(lineLBW); } - if(prefs.getBoolean("waistEnable", false)) { + if (prefs.getBoolean("waistEnable", false)) { lines.add(lineWaist); } - if(prefs.getBoolean("hipEnable", false)) { + if (prefs.getBoolean("hipEnable", false)) { lines.add(lineHip); } - if(prefs.getBoolean("boneEnable", false)) { + if (prefs.getBoolean("boneEnable", false)) { lines.add(lineBone); } @@ -427,11 +432,11 @@ private long daysBetween(Calendar startDate, Calendar endDate) { return startDate.get(Calendar.DAY_OF_YEAR) - endDate.get(Calendar.DAY_OF_YEAR); } - public void btnOnClickInsertData() - { - Intent intent = new Intent(overviewView.getContext(), DataEntryActivity.class); + public void btnOnClickInsertData() + { + Intent intent = new Intent(overviewView.getContext(), DataEntryActivity.class); startActivityForResult(intent, 1); - } + } private class PieChartLastTouchListener implements PieChartOnValueSelectListener { @@ -467,7 +472,7 @@ private class LineChartTouchListener implements LineChartOnValueSelectListener { public void onValueSelected(int lineIndex, int pointIndex, PointValue pointValue) { userSelectedData = scaleDataLastDays.get(pointIndex); - updateOnView( OpenScale.getInstance(getContext()).getScaleDataList()); + updateOnView(OpenScale.getInstance(getContext()).getScaleDataList()); } @Override diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/StatisticsFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/StatisticsFragment.java index 25276cf98..276c25492 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/StatisticsFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/StatisticsFragment.java @@ -272,38 +272,38 @@ private void updateStatistics(ArrayList scaleDataList) { info_month += String.format("Ø-"+getResources().getString(R.string.label_bmi)+": %.1f
", monthAvgBMI); lines++; - if(prefs.getBoolean("fatEnable", true)) { + if (prefs.getBoolean("fatEnable", true)) { info_week += String.format("Ø-"+getResources().getString(R.string.label_fat)+": %.1f%%
", weekAvgFat); info_month += String.format("Ø-"+getResources().getString(R.string.label_fat)+": %.1f%%
", monthAvgFat); lines++; } - if(prefs.getBoolean("muscleEnable", true)) { + if (prefs.getBoolean("muscleEnable", true)) { info_week += String.format("Ø-"+getResources().getString(R.string.label_muscle)+": %.1f%%
", weekAvgMuscle); info_month += String.format("Ø-"+getResources().getString(R.string.label_muscle)+": %.1f%%
", monthAvgMuscle); lines++; } - if(prefs.getBoolean("lbwEnable", false)) { + if (prefs.getBoolean("lbwEnable", false)) { info_week += String.format("Ø-"+getResources().getString(R.string.label_lbw)+": %.1fkg
", weekAvgLBW); info_month += String.format("Ø-"+getResources().getString(R.string.label_lbw)+": %.1fkg
", monthAvgLBW); lines++; } - if(prefs.getBoolean("waterEnable", true)) { + if (prefs.getBoolean("waterEnable", true)) { info_week += String.format("Ø-"+getResources().getString(R.string.label_water)+": %.1f%%
", weekAvgWater); info_month += String.format("Ø-"+getResources().getString(R.string.label_water)+": %.1f%%
", monthAvgWater); lines++; } - if(prefs.getBoolean("boneEnable", false)) { + if (prefs.getBoolean("boneEnable", false)) { info_week += String.format("Ø-"+getResources().getString(R.string.label_bone)+": %.1fkg
", weekAvgBone); info_month += String.format("Ø-"+getResources().getString(R.string.label_bone)+": %.1fkg
",monthAvgBone); lines++; } - if(prefs.getBoolean("waistEnable", false)) { + if (prefs.getBoolean("waistEnable", false)) { info_week += String.format("Ø-"+getResources().getString(R.string.label_waist)+": %.1fcm
", weekAvgWaist); info_month += String.format("Ø-"+getResources().getString(R.string.label_waist)+": %.1fcm
", monthAvgWaist); lines++; @@ -313,13 +313,13 @@ private void updateStatistics(ArrayList scaleDataList) { lines++; } - if(prefs.getBoolean("hipEnable", false)) { + if (prefs.getBoolean("hipEnable", false)) { info_week += String.format("Ø-"+getResources().getString(R.string.label_hip)+": %.1fcm
", weekAvgHip); info_month += String.format("Ø-"+getResources().getString(R.string.label_hip)+": %.1fcm
",monthAvgHip); lines++; } - if(prefs.getBoolean("hipEnable", false) && prefs.getBoolean("waistEnable", false)) { + if (prefs.getBoolean("hipEnable", false) && prefs.getBoolean("waistEnable", false)) { info_week += String.format("Ø-"+getResources().getString(R.string.label_whr)+": %.2f
", weekAvgWHR); info_month += String.format("Ø-"+getResources().getString(R.string.label_whr)+": %.2f
", monthAvgWHR); lines++; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java index fb670ee0f..9ec6a7154 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java @@ -74,8 +74,8 @@ import static android.util.TypedValue.COMPLEX_UNIT_DIP; public class TableFragment extends Fragment implements FragmentUpdateListener { - private View tableView; - private ListView tableDataView; + private View tableView; + private ListView tableDataView; private LinearLayout tableHeaderView; private SharedPreferences prefs; private LinearLayout subpageView; @@ -84,22 +84,22 @@ public class TableFragment extends Fragment implements FragmentUpdateListener { private int selectedSubpageNr; - public TableFragment() { - - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) - { - tableView = inflater.inflate(R.layout.fragment_table, container, false); + public TableFragment() { + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) + { + tableView = inflater.inflate(R.layout.fragment_table, container, false); subpageView = (LinearLayout) tableView.findViewById(R.id.subpageView); - tableDataView = (ListView) tableView.findViewById(R.id.tableDataView); + tableDataView = (ListView) tableView.findViewById(R.id.tableDataView); tableHeaderView = (LinearLayout) tableView.findViewById(R.id.tableHeaderView); - tableView.findViewById(R.id.btnImportData).setOnClickListener(new onClickListenerImport()); - tableView.findViewById(R.id.btnExportData).setOnClickListener(new onClickListenerExport()); + tableView.findViewById(R.id.btnImportData).setOnClickListener(new onClickListenerImport()); + tableView.findViewById(R.id.btnExportData).setOnClickListener(new onClickListenerExport()); measurementsList = new ArrayList<>(); @@ -129,11 +129,11 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa selectedSubpageNr = 0; - return tableView; - } - - @Override - public void updateOnView(ArrayList scaleDataList) + return tableView; + } + + @Override + public void updateOnView(ArrayList scaleDataList) { tableDataView.setAdapter(new ListViewAdapter(new ArrayList>())); // delete all data in the table with an empty adapter array list @@ -245,7 +245,7 @@ public void updateOnView(ArrayList scaleDataList) tableDataView.setAdapter(new ListViewAdapter(dataRowList)); tableDataView.setOnItemClickListener(new onClickListenerRow()); - } + } private int pxImageDp(float dp) { return (int)(dp * getResources().getDisplayMetrics().density + 0.5f); @@ -396,7 +396,7 @@ private class ListViewAdapter extends BaseAdapter { private ArrayList> dataList; private LinearLayout row; - public ListViewAdapter(ArrayList> list){ + public ListViewAdapter(ArrayList> list) { super(); this.dataList =list; } @@ -422,7 +422,7 @@ public View getView(int position, View convertView, ViewGroup parent) { return convertView; } - if(convertView == null){ + if (convertView == null) { row = new LinearLayout(getContext()); convertView = row; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/preferences/BackupPreferences.java b/android_app/app/src/main/java/com/health/openscale/gui/preferences/BackupPreferences.java index f94bc5314..92eeda9de 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/preferences/BackupPreferences.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/preferences/BackupPreferences.java @@ -135,12 +135,12 @@ public boolean onPreferenceClick(Preference preference) { } private boolean importBackup(String databaseName, File exportDir) { - if(!isExternalStoragePresent()) + if (!isExternalStoragePresent()) return false; File exportFile = new File(Environment.getDataDirectory() + "/data/com.health.openscale" + - "/databases/" + databaseName ); + "/databases/" + databaseName); File importFile = new File(exportDir, databaseName); if (!importFile.exists()) { @@ -161,12 +161,12 @@ private boolean importBackup(String databaseName, File exportDir) { } private boolean exportBackup(String databaseName, File exportDir) { - if(!isExternalStoragePresent()) + if (!isExternalStoragePresent()) return false; File dbFile = new File(Environment.getDataDirectory() + "/data/com.health.openscale" + - "/databases/" + databaseName ); + "/databases/" + databaseName); File file = new File(exportDir, databaseName); diff --git a/android_app/app/src/main/java/com/health/openscale/gui/preferences/UsersPreferences.java b/android_app/app/src/main/java/com/health/openscale/gui/preferences/UsersPreferences.java index 1eb83f979..b47b190bb 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/preferences/UsersPreferences.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/preferences/UsersPreferences.java @@ -82,14 +82,14 @@ private void updateUserPreferences() public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == UserSettingsActivity.ADD_USER_REQUEST) { - if(resultCode == RESULT_OK){ + if (resultCode == RESULT_OK) { updateUserPreferences(); } } if (requestCode == UserSettingsActivity.EDIT_USER_REQUEST) { - if(resultCode == RESULT_OK){ + if (resultCode == RESULT_OK) { updateUserPreferences(); } } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/BMIMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/BMIMeasurementView.java index 273e35d91..6e761d433 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/BMIMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/BMIMeasurementView.java @@ -55,11 +55,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return evalSheet.evaluateBMI(value); } - @Override - public float getMinValue() { - return 10; - } - @Override public float getMaxValue() { return 50; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/BMRMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/BMRMeasurementView.java index 365ad73dc..24b2df545 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/BMRMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/BMRMeasurementView.java @@ -55,11 +55,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return null; } - @Override - public float getMinValue() { - return 0; - } - @Override public float getMaxValue() { return 5000; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/BoneMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/BoneMeasurementView.java index 72f1c468a..d995dde6e 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/BoneMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/BoneMeasurementView.java @@ -55,11 +55,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return null; } - @Override - public float getMinValue() { - return 0; - } - @Override public float getMaxValue() { return 50; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/CommentMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/CommentMeasurementView.java index 44f701919..95deff1eb 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/CommentMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/CommentMeasurementView.java @@ -71,11 +71,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return null; } - @Override - public float getMinValue() { - return 0; - } - @Override public float getMaxValue() { return 0; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/DateMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/DateMeasurementView.java index 2a993e38b..289eb6954 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/DateMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/DateMeasurementView.java @@ -85,11 +85,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return null; } - @Override - public float getMinValue() { - return 0; - } - @Override public float getMaxValue() { return 0; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/FatMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/FatMeasurementView.java index 1b9cb3877..f1edde88f 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/FatMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/FatMeasurementView.java @@ -70,11 +70,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return evalSheet.evaluateBodyFat(value); } - @Override - public float getMinValue() { - return 10; - } - @Override public float getMaxValue() { return 80; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/HipMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/HipMeasurementView.java index b2f0b5d87..0e6b2bc72 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/HipMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/HipMeasurementView.java @@ -55,11 +55,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return null; } - @Override - public float getMinValue() { - return 30; - } - @Override public float getMaxValue() { return 200; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/LBWMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/LBWMeasurementView.java index 45026fcdd..26762ff8c 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/LBWMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/LBWMeasurementView.java @@ -70,11 +70,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return null; } - @Override - public float getMinValue() { - return 10; - } - @Override public float getMaxValue() { return 300; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/LinearGaugeView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/LinearGaugeView.java index 21587b820..bcc4bfcff 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/LinearGaugeView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/LinearGaugeView.java @@ -20,6 +20,8 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; @@ -34,17 +36,12 @@ public class LinearGaugeView extends View { public static final int COLOR_ORANGE = Color.parseColor("#FFBB33"); public static final int COLOR_RED = Color.parseColor("#FF4444"); - private final float barHeight = 10; - private final float limitLineHeight = 20; - private final float lineThickness = 5.0f; - private final float textOffset = 10.0f; + private static final float barHeight = 10; + private static final float textOffset = 10.0f; + private RectF limitRect = new RectF(0, 0, barHeight / 2, barHeight * 2); - private float firstPercent; - private float firstPos; - private float secondPercent; - private float secondPos; - private float valuePercent; - private float valuePos; + // Pre-created rect to avoid creating object in onDraw + private Rect bounds = new Rect(); private Paint rectPaintLow; private Paint rectPaintNormal; @@ -54,10 +51,8 @@ public class LinearGaugeView extends View { private Paint infoTextPaint; private float value; - private float minValue; - private float maxValue; - private float firstLimit; - private float secondLimit; + private float firstLimit = -1.0f; + private float secondLimit = -1.0f; public LinearGaugeView(Context context) { super(context); @@ -96,9 +91,23 @@ private void init() { infoTextPaint.setColor(Color.GRAY); infoTextPaint.setTextSize(30); infoTextPaint.setTextAlign(Paint.Align.CENTER); + } + + private float valueToPosition(float value, float minValue, float maxValue) { + final float percent = (value - minValue) / (maxValue - minValue) * 100.0f; + return getWidth() / 100.0f * percent; + } + + private void drawCenteredText(Canvas canvas, String text, float centerX, float y, + Paint paint, Rect textBounds) { + float x = Math.max(0.0f, centerX - textBounds.width() / 2.0f); + x = Math.min(x, getWidth() - textBounds.width()); + canvas.drawText(text, x, y, paint); + } - firstLimit = -1.0f; - secondLimit = -1.0f; + private void drawCenteredText(Canvas canvas, String text, float centerX, float y, Paint paint) { + paint.getTextBounds(text, 0, text.length(), bounds); + drawCenteredText(canvas, text, centerX, y, paint, bounds); } @Override @@ -106,57 +115,92 @@ protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (firstLimit < 0 && secondLimit < 0) { - float textY=getHeight() / 2.0f; - float textX=getWidth() / 2.0f; - canvas.drawText(getResources().getString(R.string.info_no_evaluation_available),textX,textY,infoTextPaint); + float textX = getWidth() / 2.0f; + float textY = getHeight() / 2.0f; + canvas.drawText(getResources().getString(R.string.info_no_evaluation_available), textX, textY, infoTextPaint); return; } - firstPercent = (firstLimit / maxValue) * 100.0f; - firstPos = (getWidth() / 100.0f) * firstPercent; + final boolean hasFirstLimit = firstLimit >= 0; - secondPercent = (secondLimit / maxValue) * 100.0f; - secondPos = (getWidth() / 100.0f) * secondPercent; + // Calculate the size of the "normal" span with a fallback if there is no such span + float span = hasFirstLimit ? secondLimit - firstLimit : 0.3f * secondLimit; - valuePercent = (value / maxValue) * 100.0f; - valuePos = (getWidth() / 100.0f) * valuePercent; + // Adjust the span if needed to make the value fit inside of it + if (hasFirstLimit && value < firstLimit - span) { + span = firstLimit - value; + } else if (!hasFirstLimit && value < secondLimit - span) { + span = secondLimit - value; + } else if (value > secondLimit + span) { + span = value - secondLimit; + } + + // Round span to some nice value + if (span <= 1.0f) { + span = (float)Math.ceil(span * 10.0) / 10.0f; + } else if (span <= 10.0f) { + span = (float)Math.ceil(span); + } else { + span = 5.0f * (float)Math.ceil(span / 5.0); + } + + final float minValue = Math.max(0.0f, (hasFirstLimit ? firstLimit : secondLimit) - span); + final float maxValue = secondLimit + span; + + final float firstPos = valueToPosition(firstLimit, minValue, maxValue); + final float secondPos = valueToPosition(secondLimit, minValue, maxValue); + final float valuePos = valueToPosition(value, minValue, maxValue); // Bar + final float barTop = getHeight() / 2.0f - barHeight / 2.0f; + final float barBottom = barTop + barHeight; + if (firstLimit > 0) { - canvas.drawRect(0, (getHeight() / 2.0f) - (barHeight / 2.0f), firstPos, (getHeight() / 2.0f) + (barHeight / 2.0f), rectPaintLow); + canvas.drawRect(0, barTop, firstPos, barBottom, rectPaintLow); + canvas.drawRect(firstPos, barTop, secondPos, barBottom, rectPaintNormal); } else { - canvas.drawRect(0, (getHeight() / 2.0f) - (barHeight / 2.0f), firstPos, (getHeight() / 2.0f) + (barHeight / 2.0f), rectPaintNormal); + canvas.drawRect(0, barTop, secondPos, barBottom, rectPaintNormal); } - canvas.drawRect(firstPos, (getHeight() / 2.0f) - (barHeight / 2.0f), secondPos , (getHeight() / 2.0f) + (barHeight / 2.0f), rectPaintNormal); - canvas.drawRect(secondPos,(getHeight() / 2.0f) - (barHeight / 2.0f), getWidth() , (getHeight() / 2.0f) + (barHeight / 2.0f), rectPaintHigh); + canvas.drawRect(secondPos, barTop, getWidth(), barBottom, rectPaintHigh); // Limit Lines - canvas.drawRect(0, (getHeight() / 2.0f) - (limitLineHeight / 2.0f), 0+lineThickness, (getHeight() / 2.0f) + (limitLineHeight / 2.0f), textPaint); + limitRect.offsetTo(0, getHeight() / 2.0f - limitRect.height() / 2.0f); + canvas.drawRect(limitRect, textPaint); if (firstLimit > 0) { - canvas.drawRect(firstPos, (getHeight() / 2.0f) - (limitLineHeight / 2.0f), firstPos + lineThickness, (getHeight() / 2.0f) + (limitLineHeight / 2.0f), textPaint); + limitRect.offsetTo(firstPos - limitRect.width() / 2.0f, limitRect.top); + canvas.drawRect(limitRect, textPaint); } - canvas.drawRect(secondPos, (getHeight() / 2.0f) - (limitLineHeight / 2.0f), secondPos+lineThickness, (getHeight() / 2.0f) + (limitLineHeight / 2.0f), textPaint); - canvas.drawRect(getWidth()-lineThickness, (getHeight() / 2.0f) - (limitLineHeight / 2.0f), getWidth(), (getHeight() / 2.0f) + (limitLineHeight / 2.0f), textPaint); + limitRect.offsetTo(secondPos - limitRect.width() / 2.0f, limitRect.top); + canvas.drawRect(limitRect, textPaint); + limitRect.offsetTo(getWidth() - limitRect.width(), limitRect.top); + canvas.drawRect(limitRect, textPaint); // Text - canvas.drawText(Float.toString(minValue), 0.0f, (getHeight() / 2.0f) - (barHeight / 2.0f) - textOffset, textPaint); + final float textY = barTop - textOffset; + canvas.drawText(Float.toString(minValue), 0.0f, textY, textPaint); if (firstLimit > 0) { - canvas.drawText(Float.toString(firstLimit), firstPos - 5.0f, (getHeight() / 2.0f) - (barHeight / 2.0f) - textOffset, textPaint); + drawCenteredText(canvas, Float.toString(firstLimit), firstPos, textY, textPaint); } - canvas.drawText(Float.toString(secondLimit), secondPos-5.0f, (getHeight() / 2.0f) - (barHeight / 2.0f) - textOffset, textPaint); - canvas.drawText(Float.toString(maxValue), getWidth()-40.0f, (getHeight() / 2.0f) - (barHeight / 2.0f)- textOffset, textPaint); + drawCenteredText(canvas, Float.toString(secondLimit), secondPos, textY, textPaint); + drawCenteredText(canvas, Float.toString(maxValue), getWidth(), textY, textPaint); // Indicator + final float indicatorBottom = limitRect.bottom + 10.0f; Path path = new Path(); path.setFillType(Path.FillType.EVEN_ODD); - path.moveTo(valuePos, (getHeight() / 2.0f) - 10.0f); - path.lineTo(valuePos + 10.0f, (getHeight() / 2.0f) + 20.0f); - path.lineTo(valuePos - 10.0f, (getHeight() / 2.0f) + 20.0f); - path.lineTo(valuePos, (getHeight() / 2.0f) - 10.0f); + path.moveTo(valuePos, barTop); + path.lineTo(valuePos + 10.0f, indicatorBottom); + path.lineTo(valuePos - 10.0f, indicatorBottom); + path.lineTo(valuePos, barTop); path.close(); canvas.drawPath(path, indicatorPaint); - canvas.drawText(String.format("%.2f", value), valuePos-15.0f, (getHeight() / 2.0f) - (barHeight / 2.0f) - textOffset, indicatorPaint); + + // Value text + String valueStr = String.format("%.2f", value); + indicatorPaint.getTextBounds(valueStr, 0, valueStr.length(), bounds); + drawCenteredText(canvas, valueStr, valuePos, + indicatorBottom + bounds.height() + textOffset, indicatorPaint, bounds); } @Override @@ -201,13 +245,6 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(width, height); } - public void setMinMaxValue(float min, float max) { - minValue = min; - maxValue = max; - invalidate(); - requestLayout(); - } - public void setLimits(float first, float second) { firstLimit = first; secondLimit = second; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java index 10fafc3f9..36816200d 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java @@ -77,8 +77,10 @@ public enum MeasurementViewMode {VIEW, EDIT, ADD}; private Date dateTime; private String value; + private float previousValue; private String diffValue; + private MeasurementViewUpdateListener updateListener = null; private MeasurementViewMode measurementMode; public MeasurementView(Context context, String text, Drawable icon) { @@ -197,7 +199,13 @@ public void onClick(View view) { evaluatorView.setLayoutParams(new TableRow.LayoutParams(0, LayoutParams.WRAP_CONTENT, 0.99f)); spaceAfterEvaluatorView.setLayoutParams(new TableRow.LayoutParams(0, LayoutParams.WRAP_CONTENT, 0.01f)); - measurementRow.setOnClickListener(new onClickListenerEvaluation()); + onClickListenerEvaluation onClickListener = new onClickListenerEvaluation(); + measurementRow.setOnClickListener(onClickListener); + evaluatorRow.setOnClickListener(onClickListener); + } + + public void setOnUpdateListener(MeasurementViewUpdateListener listener) { + updateListener = listener; } public abstract void updateValue(ScaleData updateData); @@ -205,7 +213,6 @@ public void onClick(View view) { public abstract void updatePreferences(SharedPreferences preferences); public abstract String getUnit(); public abstract EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value); - public abstract float getMinValue(); public abstract float getMaxValue(); public float getValue() { @@ -220,19 +227,13 @@ public float getValue() { } public void incValue() { - float incValue = getValue() + 0.1f; - - if (incValue <= getMaxValue()) { - setValueOnView(dateTime, incValue); - } + float incValue = Math.min(getMaxValue(), getValue() + 0.1f); + setValueOnView(dateTime, incValue); } public void decValue() { - float decValue = getValue() - 0.1f; - - if (decValue >= 0) { - setValueOnView(dateTime, decValue); - } + float decValue = Math.max(0.0f, getValue() - 0.1f); + setValueOnView(dateTime, decValue); } public String getValueAsString() { @@ -292,19 +293,27 @@ protected void setValueOnView(Date objTimeDate, Object objValue) { dateTime = objTimeDate; value = String.valueOf(objValue); - try{ + try { Float floatValue = Float.parseFloat(value); - if (measurementMode == VIEW) { + if (measurementMode == VIEW || measurementMode == EDIT) { evaluate(floatValue); } valueView.setText(String.format("%.2f ", floatValue) + getUnit()); value = String.valueOf(Math.round(floatValue*100.0f)/100.0f); + // Only update diff value if setDiffOnView has been called previously + if (!diffValue.isEmpty()) { + setDiffOnView(floatValue, previousValue); + } } catch (NumberFormatException e) { valueView.setText(value); } + if (updateListener != null) { + updateListener.onMeasurementViewUpdate(this); + } } protected void setDiffOnView(float value, float prevValue) { + previousValue = prevValue; float diff = value - prevValue; String symbol; @@ -313,7 +322,7 @@ protected void setDiffOnView(float value, float prevValue) { if (diff > 0.0) { symbol = SYMBOL_UP; symbol_color = "" + SYMBOL_UP + ""; - } else if (diff < 0.0){ + } else if (diff < 0.0) { symbol = SYMBOL_DOWN; symbol_color = "" + SYMBOL_DOWN + ""; } else { @@ -342,8 +351,8 @@ public void setExpand(boolean state) { } } - protected void setVisible(boolean isVisible){ - if(isVisible) { + protected void setVisible(boolean isVisible) { + if (isVisible) { measurementRow.setVisibility(View.VISIBLE); } else { measurementRow.setVisibility(View.GONE); @@ -382,11 +391,10 @@ private void evaluate(float value) { evalResult = new EvaluationResult(); } - evaluatorView.setMinMaxValue(getMinValue(), getMaxValue()); evaluatorView.setLimits(evalResult.lowLimit, evalResult.highLimit); evaluatorView.setValue(value); - switch(evalResult.eval_state) + switch (evalResult.eval_state) { case LOW: indicatorView.setBackgroundColor(ChartUtils.COLOR_BLUE); @@ -483,11 +491,7 @@ public void onClick(View v) { return; } - if (evaluatorRow.getVisibility() == View.VISIBLE) { - evaluatorRow.setVisibility(View.GONE); - } else { - evaluatorRow.setVisibility(View.VISIBLE); - } + setExpand(evaluatorRow.getVisibility() != View.VISIBLE); } } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementViewUpdateListener.java b/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementViewUpdateListener.java new file mode 100644 index 000000000..0dec3d1e4 --- /dev/null +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementViewUpdateListener.java @@ -0,0 +1,20 @@ +/* Copyright (C) 2017 Erik Johansson +* +* 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 +*/ +package com.health.openscale.gui.views; + +public interface MeasurementViewUpdateListener { + public void onMeasurementViewUpdate(MeasurementView view); +} diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/MuscleMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/MuscleMeasurementView.java index 290284a15..05299f909 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/MuscleMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/MuscleMeasurementView.java @@ -60,11 +60,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return evalSheet.evaluateBodyMuscle(value); } - @Override - public float getMinValue() { - return 10; - } - @Override public float getMaxValue() { return 80; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/TimeMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/TimeMeasurementView.java index 302201fd6..7a11cca38 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/TimeMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/TimeMeasurementView.java @@ -89,11 +89,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return null; } - @Override - public float getMinValue() { - return 0; - } - @Override public float getMaxValue() { return 0; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/WHRMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/WHRMeasurementView.java index ef9d28d3f..6684740fb 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/WHRMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/WHRMeasurementView.java @@ -60,11 +60,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return evalSheet.evaluateWHR(value); } - @Override - public float getMinValue() { - return 0.5f; - } - @Override public float getMaxValue() { return 1.5f; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/WHtRMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/WHtRMeasurementView.java index 492286216..66793e7e7 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/WHtRMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/WHtRMeasurementView.java @@ -60,11 +60,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return evalSheet.evaluateWHtR(value); } - @Override - public float getMinValue() { - return 0; - } - @Override public float getMaxValue() { return 1; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/WaistMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/WaistMeasurementView.java index 1c322e041..d37ec7c50 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/WaistMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/WaistMeasurementView.java @@ -55,11 +55,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return evalSheet.evaluateWaist(value); } - @Override - public float getMinValue() { - return 30; - } - @Override public float getMaxValue() { return 200; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/WaterMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/WaterMeasurementView.java index 846c0e55b..35e955c93 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/WaterMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/WaterMeasurementView.java @@ -70,11 +70,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return evalSheet.evaluateBodyWater(value); } - @Override - public float getMinValue() { - return 30; - } - @Override public float getMaxValue() { return 80; diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/WeightMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/WeightMeasurementView.java index 5f73b5606..2ac131358 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/WeightMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/WeightMeasurementView.java @@ -56,11 +56,6 @@ public EvaluationResult evaluateSheet(EvaluationSheet evalSheet, float value) { return evalSheet.evaluateWeight(value); } - @Override - public float getMinValue() { - return 30; - } - @Override public float getMaxValue() { return 300; diff --git a/android_app/app/src/main/res/drawable/rect_normal.xml b/android_app/app/src/main/res/drawable/rect_normal.xml index 08cb20d68..c5c3b9974 100644 --- a/android_app/app/src/main/res/drawable/rect_normal.xml +++ b/android_app/app/src/main/res/drawable/rect_normal.xml @@ -1,7 +1,7 @@ - + diff --git a/android_app/app/src/main/res/layout-large/fragment_overview.xml b/android_app/app/src/main/res/layout-large/fragment_overview.xml index 781186ac3..501ff4dd9 100644 --- a/android_app/app/src/main/res/layout-large/fragment_overview.xml +++ b/android_app/app/src/main/res/layout-large/fragment_overview.xml @@ -46,6 +46,7 @@ diff --git a/android_app/app/src/main/res/values-es/strings.xml b/android_app/app/src/main/res/values-es/strings.xml new file mode 100644 index 000000000..aa4687266 --- /dev/null +++ b/android_app/app/src/main/res/values-es/strings.xml @@ -0,0 +1,182 @@ + + + + openScale + General + Gráfica + Tabla + Estadísticas + Usuarios + Datos + Mediciones + Acerca de + + Configuración + Estado del Bluetooth + + Añadir + Cancelar + OK + Si + No + Borrar + Añadir usuario + + Id + Peso + Índice de masa corporal (IMC) + Tasa metabólica basal (TMB) + Porcentaje de grasa corporal + Porcentaje de agua + Porcentaje muscular + Masa corporal magra + Circunferencia de la cintura + Circunferencia de la cadera + Comentario + Proporción cintura-altura + Proporción cintura-cadera + Masa ósea + Asignación inteligente de usuario + + días + medidas + Últimos 7 días + Últimos 30 días + Diferencia de peso + La fecha para cumplir el objetivo es + Días restantes + + Fecha + Hora + F. Nacimiento + Nombre + Altura + Unidad + Género + Hombre + Mujer + Peso objetivo + Fecha objetivo + + + usuario + última medición + objetivo + estadísticas + + Importar + Exportar + Borrar todo + + Se requiere un valor + El valor no está en el rango + Error exportando + Error importando + Error, se require un nombre de usuario + Error, se requiere la altura + Error, se requiere el peso inicial + Error, se requiere el objetivo de peso + se requiere circunferencia de la cadera + + Entrada borrada + Todas las entradas borradas + Datos exportados a + Datos importados de + Establecer nombre de archivo a + Introduzca valor en cm + Introduzca valor en % + Introduzca valor en + Introduzca un comentario opcional + Introduzca su peso inicial en su unidad de medida + Introduzca su peso objetivo en su unidad de medida + está visible + no está visible + está activado + está desactivado + no está disponible + Borrar todos los datos de Bluetooth + Los datos de Bluetooth fueron borrados + Intentando conectar a + Se perdió la conexión Bluetooth. + No se encontró un dispositivo Bluetooth + La conexión se estableció correctamente + Inicializar el dispositivo Bluetooth + El Bluetooth encontró un error inesperado + %1$.2f%2$s [%3$s] a %4$s añadido + + Introduce tu nombre + No existe usuario. Por favor, crea un nuevo usuario en la configuración. + No se puede evaluar el valor + + ¿Realmente quieres borrar la entrada de la base de datos? + ¿Realmente quieres borrar todas las entradas de la base de datos? + ¿Realmente quieres borrar el usuario? + + Bluetooth + Buscar báscula al iniciar + Buscando básculas Bluetooth + Tipo de dispositivo + + Etiqueta en el punto de medición + Mostrar un punto en la medición + + Confirmación de borrado + + Estimación de agua corporal + Estimación de masa corporal magra + Estimación de grasa coporal + + Mostrar + Estimación de métricas corporales + Base de datos de mediciones + Varios + + Responsable + Página Web + Licencia + + Fórmula de agua corporal + Fórmula de masa corporal magra + Fórmula de grasa corporal + automático + + Recordatorio + Días de la semana + Hora + Texto de la notificación + Es hora de pesarse + + Tu peso era + Tu masa corporal era + Tu porcentaje de agua era + Tu porcentaje muscular era + Tu cintura era + Tu cadera era + el + + Lunes + Martes + Miércoles + Jueves + Viernes + Sábado + Domingo + dispositivo no soportado + Exportar respaldo + Importar respaldo + Respaldo + Directorio de exportación + no encontrado + Ignorar los datos fuera de rango + Peso inicial + Calcular media por día/mes + Línea de peso de regresión + Línea de grado de polinomio de regresión + Línea del objetivo + + + Número máximo de usuarios de báscula concurrentes alcanzado. + Por favor, póngase descalzo en la báscula para tomar medidas de referencia. + Medición de peso: %.2f + + diff --git a/android_app/app/src/main/res/values-fr/strings.xml b/android_app/app/src/main/res/values-fr/strings.xml index da6f8632e..35cd961f3 100644 --- a/android_app/app/src/main/res/values-fr/strings.xml +++ b/android_app/app/src/main/res/values-fr/strings.xml @@ -23,7 +23,7 @@ ID Poids IMC - Taux de graisse corporelle + Pourcentage de graisse corporelle Pourcentage d\'eau Pourcentage musculaire Tour de taille @@ -136,4 +136,6 @@ Dimanche Statistiques Entrez votre objectif de poids dans votre unité d\'échelle + Masse osseuse + Taux métabolique basal (BMR) diff --git a/android_app/app/src/main/res/values-pl/strings.xml b/android_app/app/src/main/res/values-pl/strings.xml index 42f4f64dd..562287091 100644 --- a/android_app/app/src/main/res/values-pl/strings.xml +++ b/android_app/app/src/main/res/values-pl/strings.xml @@ -35,7 +35,7 @@ Stosunek obwodu talii do obwodu bioder Masa kostna Inteligente przypisywanie użytkowników - + dni pomiarów Ostatnie 7 dni diff --git a/android_app/app/src/main/res/values-sv/strings.xml b/android_app/app/src/main/res/values-sv/strings.xml new file mode 100644 index 000000000..fc6c5c62f --- /dev/null +++ b/android_app/app/src/main/res/values-sv/strings.xml @@ -0,0 +1,156 @@ + + + openScale + Översikt + Graf + Tabell + Statistik + Användare + Data + Mätningar + Om + Inställningar + Bluetooth status + Lägg till + Avbryt + Ok + Ja + Nej + Ta bort + Lägg till användare + Id + Vikt + Kroppsmasseindex (BMI) + Basalomsättning (BMR) + Procentdel kroppsfett + Procentdel vatten + Måndag + Tisdag + Onsdag + Torsdag + Fredag + Lördag + Söndag + Backup + Dags att väga + Din vikt var + Din mängd kroppsfett var + Din procentdel vatten var + Din procentdel muskler var + Tid + Veckodagar + Hemsida + License + Diverse + Fel vid export + Kön + Man + Kvinna + Målvikt + Måldatum + användare + senaste mätning + mål + Datum + Tid + Födelsedag + Namn + Längd + Viktenhet + Dagar kvar + Måldatum är + Viktskillnad + dagar + mätningar + Senast 7 dagarna + Senast 30 dagarna + Procentdel muskler + Fettfri kroppsvikt + Midjeomkrets + Höftomkrets + Kommentar + Midja-höft-kvot + Midja-till-längd-kvot + Benmassa + Smart tilldelning av användare + statistik + Import + Export + Ta bort alla + Värde krävs + Värdet är inte inom gränserna + Fel vid import + Fel: användarnamn krävs + Fel: längd krävs + Fel: initial vikt krävs + Fel: målvikt krävs + Höftomkrets krävs + Databaspost borttagen + Alla databasposter borttagna + Data exporterad till + Data importerad från + Sätt filnamn till + Ange värde i cm + Ange värde i % + Ange värde i + Ange en frivillig kommentar + Ange din initiala vikt i din viktenhet + Ange din målvikt i din viktenhet + är synlig + är inte synlig + är påslagen + är avslagen + är inte tillgänglig + Rensa all Bluetooth-data + Bluetooth-datan togs bort + Försöker ansluta till + Tappade Bluetooth-anslutningen. + Ingen Bluetooth-enhet funnen + Anslutning upprättad + Initiera Bluetooth-enhet + Bluetooth stötte på ett oväntat fel + La till %1$.2f%2$s [%3$s] till %4$s + Ange ditt namn + Ingen användare finns. Skapa en ny användare i inställningarna. + Kan inte evaluera värdet + Vill du verkligen ta bort databasposten? + Vill du verkligen ta bort alla databasposter? + Vill du verkligen ta bort användaren? + Bluetooth + Sök efter våg vid start + Söker efter Bluetooth-våg + Enhetstyp + Etikett på datapunkt + Punkt på datapunkt + Fråga vid borttagande + Estimera kroppsvatten + Estimera fettfri kroppsvikt + Estimera kroppsfett + Visa + Kroppmätetals-estimering + Mätningsdatabas + Maintainer + Kroppsvattenformel + Fettfri kroppsvikt-formel + Kroppsfettformel + auto + Påminnelse + Meddelandetext + Din midjeomkrets var + Din höftomkrets var + + enheten stöds inte + Export backup + Import backup + Exportkatalog + hittades inte + Ignorera data utanför gränserna + Initial vikt + Beräkna medelvärde per dag/månad + Regressionsviktlinje + Regressions-polynom-gradtal + Mållinje + Maximalt antal samtidiga våganvändare har nåtts. + Kliv upp barfota på vågen för referensmätningar. + Mäter vikt: %.2f + \ No newline at end of file diff --git a/android_app/app/src/main/res/values-tr/strings.xml b/android_app/app/src/main/res/values-tr/strings.xml new file mode 100644 index 000000000..f7fea94b6 --- /dev/null +++ b/android_app/app/src/main/res/values-tr/strings.xml @@ -0,0 +1,180 @@ + + + openScale + Genel Bakýþ + Çizelge + Tablo + Ýstatistik + Kullanýcý + Veri + Ölçüler + Yaklaþýk + + Ayarlar + Bluetooth Konumu + + Ekle + Ýptal + Tamam + Evet + Hayýr + Sil + Kullanýcý ekle + + Id + Aðýrlýk + Vucüt Kitle Endeksi (BMI) + Bazal Metabolik Oraný (BMR) + Vücüt Yað Yüzdesi + Su Yüzdesi + Kas Yüzdesi + Yaðsýz vücüt aðýrlýðý + Bel çevresi + Kalça çevresi + Yorum + Bel-Boy oraný + Bel-Kalça oraný + Kemik kütlesi + Akýllý kullanýcý atamasý + + Günler + Ölçüler + Son 7 Gün + Son 30 Gün + Aðýrlýk farký + Hedef tarihi + Geçen günler + + Tarih + Zaman + Doðum Tarihi + Ýsim + Boy uzunluðu + Ölçek birimi + Cinsiyet + Erkek + Kadýn + Hedef Kilo + Hedef Tarihi + + + Kullanýcý + Son ölçüm + Hedef + Ýstatistik + + Import + Export + Hepsini Sil + + Deðer gerekli + Deðer aralýkta deðil + Hatalý export + Hatalý import + Hata: kullanýcý adý gerekiyor + Error: Vücut boyu gerekli + Error: Baþlangýç aðýrlýðý gerekli + Error: Hedef aðýrlýk gerekli + Kalça çevre aðýrlýðý gerekli + + Database entry deleted + Veri tabaný giriþi silindi + Veri dýþarý aktarma + Veri içeri aktarma + Dosya adýný ayarla + Deðeri cm olarak girin + Deðeri % olarak girin + Ýçine deðer girin + Ýsteðebaðlý açýklama girin + Kendi baþlangýç aðýrlýðýnýzý girin + Kendi Hedef hedef kilonuzu girin + görünür + görünmez + etkindir + etkin deðildir + Mevcut deðil + Tüm Bluetooth verisini sil + Bluetooth veri silinmesi baþarýlý oldu + Baðlanmaya çalýþýyorsunuz + Bluetooth baðlantýsý koptu + Bluetooth cihazý bulunamadý + Baðlantý baþarýyla kuruldu + Bluetooth cihazý bulunmaya çalýþýlýyor + Beklenmedik Bluetooth hatasý + %1$.2f%2$s [%3$s] to %4$s added + + Ýsminizi girin + Kullanýcý bulunmuyor. Lütfen ayarlardan yeni kullanýcý oluþturun. + Can\'t evaluate the value + + Veri tabanýný gerçekten silmek istiyormusunuz? + Tüm girilen verileri gerçekten silmek istiyormusunuz? + Kullanýcýyý gerçekten silmek istiyormusunuz? + + Bluetooth + Baskülü aramaya baþlandý + Bluetooth Baskül aranýyor + Cihaz Tipi + + Label on data point + Point on data point + + Delete confirmation + + Tahmini Vücüt suyu oraný + Tahmini Yaðsýz vücüt oraný + Tahmini Vücüt yað oraný + + Display + Vücüt ölçütleri tahmini + Ölçüm veritabaný + Miscellaneous + + Maintainer + Websitesi + Lisan + + Vücüt oraný hesaplama formulü + Yað oraný hesaplama formulü + Vücut yaðý formülü + otomatik + + Hatýrlatma + Hafta içi + Zaman + Bildirim metni + Aðýrlýk zamaný + + Kilonuz + Yað oranýnýz + Su oraný yüzdeniz + Kas oraný yüzdeniz + Bel çevreniz + Kalça çevreniz + Üzerinde + + Pazartesi + Salý + Çarþamba + Perþembe + Cuma + Cumartesi + Pazar + Cihazýnýz desteklenmiyor + Export yedekleme + Import yedekleme + Yedekleme + Export rehberi + Bulunamadý + Mesafenin dýþýndaki verileri yoksay + Baþlangýç ??aðýrlýðý + Ortalama hesap Günlük/Aylýk + Regresyon aðýrlýk çizgisi + Regresyon polinom derecesi + Hedef çizgisi + + + Maksimum eþzamanlý ölçekli kullanýcý sayýsý ulaþtý. + Referans ölçümleri için lütfen ölçekte çýplak ayakla adým atýn. + Aðýrlýðý ölçme: %.2f + \ No newline at end of file diff --git a/android_app/app/src/main/res/values/strings.xml b/android_app/app/src/main/res/values/strings.xml index 34920ba83..5d2baf0d3 100644 --- a/android_app/app/src/main/res/values/strings.xml +++ b/android_app/app/src/main/res/values/strings.xml @@ -72,10 +72,10 @@ The value is not in range Error exporting Error importing - Error user name is required - Error body height is required - Error initial weight is required - Error goal weight is required + Error: user name is required + Error: body height is required + Error: initial weight is required + Error: goal weight is required hip circumference is required Database entry deleted diff --git a/android_app/build.gradle b/android_app/build.gradle index 8674409cc..9d39e017e 100644 --- a/android_app/build.gradle +++ b/android_app/build.gradle @@ -1,10 +1,11 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { + google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.0.1' } } diff --git a/android_app/gradle/wrapper/gradle-wrapper.properties b/android_app/gradle/wrapper/gradle-wrapper.properties index 911033970..4910d7894 100644 --- a/android_app/gradle/wrapper/gradle-wrapper.properties +++ b/android_app/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Mar 05 12:16:00 CET 2017 +#Mon Nov 20 21:08:22 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/android_app/upload_apk.sh b/android_app/upload_apk.sh old mode 100644 new mode 100755 index 36c651961..507b32c23 --- a/android_app/upload_apk.sh +++ b/android_app/upload_apk.sh @@ -1,2 +1,4 @@ - # copy apk file to home - cp app/build/outputs/apk/app-debug.apk $HOME/openScale-dev-build.apk +#!/bin/sh + +# copy apk file to home +cp app/build/outputs/apk/debug/app-debug.apk $HOME/openScale-dev-build.apk diff --git a/doc/scales/exingtech_y1.jpg b/doc/scales/exingtech_y1.jpg new file mode 100644 index 000000000..ccd377ae3 Binary files /dev/null and b/doc/scales/exingtech_y1.jpg differ