diff --git a/.travis.yml b/.travis.yml index 2ee34708..dcc74e71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,18 @@ android: - android-24 - extra-android-m2repository +deploy: + provider: releases + api-key: $GITHUB_API_KEY + file: $HOME/openScale-dev-build.apk + skip_cleanup: true + name: "openScale dev build" + body: "Automatically openScale dev build by Travis CI" + prerelease: true + overwrite: true + after_success: - chmod +x ./upload_apk.sh - ./upload_apk.sh -script: cd android_app && ./gradlew assembleDebug +script: cd android_app && ./gradlew assembleDebug \ No newline at end of file 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 071514e7..e36d311c 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 abstract class BluetoothCommunication { 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, SANITAS_SBF70, MEDISANA_BS444, DIGOO_DGS038H, EXCELVANT_CF369BLE, YUNMAI_MINI} + public enum BT_DEVICE_ID {CUSTOM_OPENSCALE, MI_SCALE_V1, SANITAS_SBF70, MEDISANA_BS444, DIGOO_DGS038H, EXCELVANT_CF369BLE, YUNMAI_MINI, MI_SCALE_V2} protected Context context; @@ -81,6 +81,8 @@ public abstract class BluetoothCommunication { return new BluetoothCustomOpenScale(context); case MI_SCALE_V1: return new BluetoothMiScale(context); + case MI_SCALE_V2: + return new BluetoothMiScale2(context); case SANITAS_SBF70: return new BluetoothSanitasSbf70(context); case MEDISANA_BS444: diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMiScale2.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMiScale2.java new file mode 100644 index 00000000..59c960a3 --- /dev/null +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothMiScale2.java @@ -0,0 +1,291 @@ +/* Copyright (C) 2014 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 android.util.Log; + +import com.health.openscale.core.OpenScale; +import com.health.openscale.core.datatypes.ScaleData; +import com.health.openscale.core.datatypes.ScaleUser; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.Random; +import java.util.UUID; + +import static com.health.openscale.core.bluetooth.BluetoothCommunication.BT_STATUS_CODE.BT_UNEXPECTED_ERROR; + +public class BluetoothMiScale2 extends BluetoothCommunication { + private final UUID WEIGHT_MEASUREMENT_SERVICE = UUID.fromString("0000181b-0000-1000-8000-00805f9b34fb"); + private final UUID WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC = UUID.fromString("00002a2f-0000-3512-2118-0009af100700"); + private final UUID WEIGHT_MEASUREMENT_TIME_CHARACTERISTIC = UUID.fromString("00002a2b-0000-1000-8000-00805f9b34fb"); + private final UUID WEIGHT_MEASUREMENT_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + private final UUID WEIGHT_CUSTOM_SERVICE = UUID.fromString("00001530-0000-3512-2118-0009af100700"); + private final UUID WEIGHT_CUSTOM_CONFIG = UUID.fromString("00001542-0000-3512-2118-0009af100700"); + + public BluetoothMiScale2(Context context) { + super(context); + } + + @Override + public String deviceName() { + return "Xiaomi Mi Scale v2"; + } + + @Override + public String defaultDeviceName() { + return "MIBCS"; + } + + @Override + public void onBluetoothDataRead(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic, int status) { + byte[] data = gattCharacteristic.getValue(); + + int currentYear = Calendar.getInstance().get(Calendar.YEAR); + int currentMonth = Calendar.getInstance().get(Calendar.MONTH)+1; + int currentDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH); + int scaleYear = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF); + int scaleMonth = (int) data[2]; + int scaleDay = (int) data[3]; + + if (currentYear == scaleYear && currentMonth == scaleMonth && currentDay == scaleDay) { + setBtMachineState(BT_MACHINE_STATE.BT_CMD_STATE); + } else { + Log.d("BluetoothMiScale", "Current year and scale year is different"); + } + } + + @Override + public void onBluetoothDataChange(BluetoothGatt bluetoothGatt, BluetoothGattCharacteristic gattCharacteristic) { + final byte[] data = gattCharacteristic.getValue(); + + if (data != null && data.length > 0) { + // Stop command from mi scale received + if (data[0] == 0x03) { + setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE); + } + + if (data.length == 26) { + final byte[] firstWeight = Arrays.copyOfRange(data, 0, 10); + final byte[] secondWeight = Arrays.copyOfRange(data, 10, 20); + parseBytes(firstWeight); + parseBytes(secondWeight); + } + + if (data.length == 13) { + parseBytes(data); + } + + } + } + + + @Override + boolean nextInitCmd(int stateNr) { + switch (stateNr) { + case 0: + // read device time + readBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_TIME_CHARACTERISTIC); + break; + case 1: + // set current time + Calendar currentDateTime = Calendar.getInstance(); + int year = currentDateTime.get(Calendar.YEAR); + byte month = (byte)(currentDateTime.get(Calendar.MONTH)+1); + byte day = (byte)currentDateTime.get(Calendar.DAY_OF_MONTH); + byte hour = (byte)currentDateTime.get(Calendar.HOUR_OF_DAY); + byte min = (byte)currentDateTime.get(Calendar.MINUTE); + byte sec = (byte)currentDateTime.get(Calendar.SECOND); + + byte[] dateTimeByte = {(byte)(year), (byte)(year >> 8), month, day, hour, min, sec, 0x03, 0x00, 0x00}; + + writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_TIME_CHARACTERISTIC, dateTimeByte); + break; + case 2: + // set notification on for weight measurement history + setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, WEIGHT_MEASUREMENT_CONFIG); + break; + case 3: + // Set on history weight measurement + byte[] magicBytes = new byte[]{(byte)0x01, (byte)0x96, (byte)0x8a, (byte)0xbd, (byte)0x62}; + + writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, magicBytes); + break; + default: + return false; + } + + return true; + } + + @Override + boolean nextBluetoothCmd(int stateNr) { + switch (stateNr) { + case 0: + // set notification on for weight measurement history + setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, WEIGHT_MEASUREMENT_CONFIG); + break; + case 1: + // set notification on for weight measurement + // FIXME: replacement characteristic for realtime measurements on Mi Scale 2? + //setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_CHARACTERISTIC, WEIGHT_MEASUREMENT_CONFIG); + break; + case 2: + // configure scale to get only last measurements + int uniqueNumber = getUniqueNumber(); + + byte[] userIdentifier = new byte[]{(byte)0x01, (byte)0xFF, (byte)0xFF, (byte) ((uniqueNumber & 0xFF00) >> 8), (byte) ((uniqueNumber & 0xFF) >> 0)}; + writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, userIdentifier); + break; + case 3: + // set notification off for weight measurement history + setNotificationOff(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, WEIGHT_MEASUREMENT_CONFIG); + break; + case 4: + // set notification on for weight measurement history + setNotificationOn(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, WEIGHT_MEASUREMENT_CONFIG); + break; + case 5: + // invoke receiving history data + writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, new byte[]{0x02}); + break; + case 6: + // set scale units + final ScaleUser selectedUser = OpenScale.getInstance(context).getSelectedScaleUser(); + byte[] setUnitCmd = new byte[]{(byte)0x06, (byte)0x04, (byte)0x00, (byte) selectedUser.scale_unit}; + writeBytes(WEIGHT_CUSTOM_SERVICE, WEIGHT_CUSTOM_CONFIG, setUnitCmd); + break; + default: + return false; + } + + return true; + } + + @Override + boolean nextCleanUpCmd(int stateNr) { + + switch (stateNr) { + case 0: + // send stop command to mi scale + writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, new byte[]{0x03}); + break; + case 1: + // acknowledge that you received the last history data + int uniqueNumber = getUniqueNumber(); + + byte[] userIdentifier = new byte[]{(byte)0x04, (byte)0xFF, (byte)0xFF, (byte) ((uniqueNumber & 0xFF00) >> 8), (byte) ((uniqueNumber & 0xFF) >> 0)}; + writeBytes(WEIGHT_MEASUREMENT_SERVICE, WEIGHT_MEASUREMENT_HISTORY_CHARACTERISTIC, userIdentifier); + break; + default: + return false; + } + + return true; + } + + private void parseBytes(byte[] weightBytes) { + try { + float weight = 0.0f; + + final byte ctrlByte0 = weightBytes[0]; + final byte ctrlByte1 = weightBytes[1]; + + final boolean isWeightRemoved = isBitSet(ctrlByte1, 7); // FIXME: unconfirmed + final boolean isStabilized = isBitSet(ctrlByte1, 5); // FIXME: unconfirmed + final boolean isLBSUnit = isBitSet(ctrlByte0, 0); + final boolean isCattyUnit = isBitSet(ctrlByte1, 6); + + // Only if the value is stabilized and the weight is *not* removed, the date is valid + if (isStabilized && !isWeightRemoved) { + + final int year = ((weightBytes[3] & 0xFF) << 8) | (weightBytes[2] & 0xFF); + final int month = (int) weightBytes[4]; + final int day = (int) weightBytes[5]; + final int hours = (int) weightBytes[6]; + final int min = (int) weightBytes[7]; + final int sec = (int) weightBytes[8]; + + if (isLBSUnit || isCattyUnit) { + weight = (float) (((weightBytes[12] & 0xFF) << 8) | (weightBytes[11] & 0xFF)) / 100.0f; + } else { + weight = (float) (((weightBytes[12] & 0xFF) << 8) | (weightBytes[11] & 0xFF)) / 200.0f; + } + + String date_string = year + "/" + month + "/" + day + "/" + hours + "/" + min; + Date date_time = new SimpleDateFormat("yyyy/MM/dd/HH/mm").parse(date_string); + + // Is the year plausible? Check if the year is in the range of 20 years... + if (validateDate(date_time, 20)) { + ScaleData scaleBtData = new ScaleData(); + + scaleBtData.setWeight(weight); + scaleBtData.setDateTime(date_time); + + addScaleData(scaleBtData); + } else { + Log.e("BluetoothMiScale", "Invalid Mi scale weight year " + year); + } + } + } catch (ParseException e) { + setBtStatus(BT_UNEXPECTED_ERROR, "Error while decoding bluetooth date string (" + e.getMessage() + ")"); + } + } + + private boolean validateDate(Date weightDate, int range) { + + Calendar currentDatePos = Calendar.getInstance(); + currentDatePos.add(Calendar.YEAR, range); + + Calendar currentDateNeg = Calendar.getInstance(); + currentDateNeg.add(Calendar.YEAR, -range); + + if (weightDate.before(currentDatePos.getTime()) && weightDate.after(currentDateNeg.getTime())) { + return true; + } + + return false; + } + + private int getUniqueNumber() { + int uniqueNumber; + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + + uniqueNumber = prefs.getInt("uniqueNumber", 0x00); + + if (uniqueNumber == 0x00) { + Random r = new Random(); + uniqueNumber = r.nextInt(65535 - 100 + 1) + 100; + + prefs.edit().putInt("uniqueNumber", uniqueNumber).commit(); + } + + int userId = prefs.getInt("selectedUserId", -1); + + return uniqueNumber + userId; + } +} 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 662e11ab..62a71db4 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 @@ -26,15 +26,23 @@ import android.text.Html; import android.text.InputType; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.Space; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; +import android.os.Handler; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnTouchListener; import com.health.openscale.R; import com.health.openscale.core.OpenScale; @@ -59,6 +67,9 @@ public abstract class MeasurementView extends TableLayout { private ImageView iconView; private TextView nameView; private TextView valueView; + private LinearLayout incdecLayout; + private Button incView; + private Button decView; private ImageView editModeView; private ImageView indicatorView; @@ -90,17 +101,22 @@ public abstract class MeasurementView extends TableLayout { iconView = new ImageView(context); nameView = new TextView(context); valueView = new TextView(context); + incView = new Button(context); + decView = new Button(context); editModeView = new ImageView(context); indicatorView = new ImageView(context); evaluatorRow = new TableRow(context); evaluatorView = new LinearGaugeView(context); + incdecLayout = new LinearLayout(context); + measurementRow.setLayoutParams(new TableRow.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT, 1.0f)); measurementRow.setGravity(Gravity.CENTER); measurementRow.addView(iconView); measurementRow.addView(nameView); measurementRow.addView(valueView); + measurementRow.addView(incdecLayout); measurementRow.addView(editModeView); measurementRow.addView(indicatorView); @@ -113,7 +129,7 @@ public abstract class MeasurementView extends TableLayout { nameView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); nameView.setTextColor(Color.BLACK); nameView.setLines(2); - nameView.setLayoutParams(new TableRow.LayoutParams(0, LayoutParams.WRAP_CONTENT, 0.60f)); + nameView.setLayoutParams(new TableRow.LayoutParams(0, LayoutParams.WRAP_CONTENT, 0.55f)); valueView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); valueView.setTextColor(Color.BLACK); @@ -121,6 +137,50 @@ public abstract class MeasurementView extends TableLayout { valueView.setPadding(0,0,20,0); valueView.setLayoutParams(new TableRow.LayoutParams(0, LayoutParams.MATCH_PARENT, 0.29f)); + incdecLayout.setOrientation(VERTICAL); + incdecLayout.addView(incView); + incdecLayout.addView(decView); + incdecLayout.setVisibility(View.GONE); + incdecLayout.setPadding(0,0,0,0); + incdecLayout.setLayoutParams(new TableRow.LayoutParams(0, LayoutParams.MATCH_PARENT, 0.05f)); + + incView.setText("+"); + incView.setBackgroundColor(Color.TRANSPARENT); + incView.setPadding(0,0,0,0); + incView.setLayoutParams(new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, 0, 0.50f)); + incView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + incValue(); + } + }); + incView.setOnTouchListener(new RepeatListener(400, 100, new OnClickListener() { + @Override + public void onClick(View view) { + incValue(); + } + })); + incView.setVisibility(View.GONE); + + decView.setText("-"); + decView.setBackgroundColor(Color.TRANSPARENT); + decView.setPadding(0,0,0,0); + decView.setLayoutParams(new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, 0, 0.50f)); + decView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + decValue(); + } + }); + + decView.setOnTouchListener(new RepeatListener(400, 100, new OnClickListener() { + @Override + public void onClick(View view) { + decValue(); + } + })); + decView.setVisibility(View.GONE); + editModeView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_editable)); editModeView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); editModeView.setVisibility(View.GONE); @@ -157,6 +217,22 @@ public abstract class MeasurementView extends TableLayout { return Float.valueOf(value); } + public void incValue() { + float incValue = getValue() + 0.1f; + + if (incValue <= getMaxValue()) { + setValueOnView(incValue); + } + } + + public void decValue() { + float decValue = getValue() - 0.1f; + + if (decValue >= 0) { + setValueOnView(decValue); + } + } + public String getValueAsString() { return value; } @@ -176,13 +252,26 @@ public abstract class MeasurementView extends TableLayout { case VIEW: indicatorView.setVisibility(View.VISIBLE); editModeView.setVisibility(View.GONE); + incdecLayout.setVisibility(View.GONE); + incView.setVisibility(View.GONE); + decView.setVisibility(View.GONE); break; case EDIT: case ADD: editModeView.setVisibility(View.VISIBLE); + incView.setVisibility(View.VISIBLE); + decView.setVisibility(View.VISIBLE); + incdecLayout.setVisibility(View.VISIBLE); if (!isEditable()) { editModeView.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_noteeditable)); + incView.setVisibility(View.GONE); + decView.setVisibility(View.GONE); + } + + if (getUnit() == null) { + incView.setVisibility(View.GONE); + decView.setVisibility(View.GONE); } indicatorView.setVisibility(View.GONE); @@ -334,7 +423,7 @@ public abstract class MeasurementView extends TableLayout { input.setInputType(getInputType()); input.setHint(getHintText()); input.setText(value); - input.setSelection(value.length()); + input.setSelectAllOnFocus(true); builder.setView(input); builder.setPositiveButton(getResources().getString(R.string.label_ok), null); @@ -396,5 +485,65 @@ public abstract class MeasurementView extends TableLayout { } } } + + private class RepeatListener implements OnTouchListener { + + private Handler handler = new Handler(); + + private int initialInterval; + private final int normalInterval; + private final OnClickListener clickListener; + + private Runnable handlerRunnable = new Runnable() { + @Override + public void run() { + handler.postDelayed(this, normalInterval); + clickListener.onClick(downView); + } + }; + + private View downView; + + /** + * RepeatListener cyclically runs a clickListener, emulating keyboard-like behaviour. First + * click is fired immediately, next one after the initialInterval, and subsequent ones after the normalInterval. + * + * @param initialInterval The interval after first click event + * @param normalInterval The interval after second and subsequent click events + * @param clickListener The OnClickListener, that will be called periodically + */ + public RepeatListener(int initialInterval, int normalInterval, + OnClickListener clickListener) { + if (clickListener == null) + throw new IllegalArgumentException("null runnable"); + if (initialInterval < 0 || normalInterval < 0) + throw new IllegalArgumentException("negative interval"); + + this.initialInterval = initialInterval; + this.normalInterval = normalInterval; + this.clickListener = clickListener; + } + + public boolean onTouch(View view, MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + handler.removeCallbacks(handlerRunnable); + handler.postDelayed(handlerRunnable, initialInterval); + downView = view; + downView.setPressed(true); + clickListener.onClick(view); + return true; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + handler.removeCallbacks(handlerRunnable); + downView.setPressed(false); + downView = null; + return true; + } + + return false; + } + + } } 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 73def5ff..9b1bd472 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 @@ -70,7 +70,7 @@ public class TimeMeasurementView extends MeasurementView { @Override public String getUnit() { - return ""; + return null; } @Override 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 658ef3a3..be7c1a32 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 @@ -34,10 +34,6 @@ public class WeightMeasurementView extends MeasurementView { @Override public void updateValue(ScaleData updateData) { setValueOnView(updateData.getConvertedWeight(getScaleUser().scale_unit)); - - if (getMeasurementMode() == MeasurementViewMode.ADD) { - getInputDialog().show(); - } } @Override diff --git a/android_app/app/src/main/res/values-pl/strings.xml b/android_app/app/src/main/res/values-pl/strings.xml new file mode 100644 index 00000000..42f4f64d --- /dev/null +++ b/android_app/app/src/main/res/values-pl/strings.xml @@ -0,0 +1,162 @@ + + + + openScale + Przegląd + Wykresy + Tabele + Statystyki + Użytkownicy + Dane + Pomiary + + Ustawienia + Stan Bluetooth + + Dodaj + Anuluj + OK + Tak + Nie + Usuń + Dodaj użytkownika + + Id + Waga + Wskaźnik masy ciała (BMI) + Wskaźnik podstawowej przemiany materii (BMR) + Procent tkanki tłuszczowej + Procent wody organizmie + Procent masy mięśniowej + Obwód talii + Obwód bioder + Komentarz + Stosunek talii do wzrostu + Stosunek obwodu talii do obwodu bioder + Masa kostna + Inteligente przypisywanie użytkowników + + dni + pomiarów + Ostatnie 7 dni + Ostatnie 30 dni + Różnica wagi + Data celu to + Pozostało dni + + Data + Czas + Urodziny + Imie + Wzrost + Jednostka wagi + Płęć + Mężczyzna + Kobieta + Docelowa waga + Data celu + + + użytkownik + ostatni pomiar + cel + statystyki + + Import + Export + Usuń wszystko + + Wartość jest wymagana + Wartość nie jest w zakresie + Błąd eksportu + Błąd importu + Błąd nazwa użytkownika jest wymagana + Błąd wzrost jest wymagany + Błąd waga początkowa jest wymagana + Błąd waga docelowa jest wymagana + Obwód bioder jest wymagany + + Wpis w bazie danych usunięty + Wszytkie wpisy w bazie danych usunięte + Dane wyeksportowane do + Dane zaimportowane z + Ustaw nazwę pliku na + Wprowadź wartość w cm + Wprowadź wartość w % + Wprowadź wartość w + Wprowadź opcjonlany komentarz + Wprowadź twoją wagę początkową w wybranej jednostce wagi + Wprowadź twoją wagę docelową w wybranej jednostce wagi + jest widoczne + nie jest widoczne + jest włączone + jest wyłączone + jest niedostępne + Wyczyść wszystkie dane Bluetooth + Dane Bluetooth usunięte + Próba połączenia do + Utracono połączenie Bluetooth. + Nie znaleziono urządzeń Bluetooth + Udało się nawiązać połączenie + Inicjalizacja urządzeń Bluetooth + Nieznany błąd Bluetooth + %1$.2f%2$s [%3$s] dodano do %4$s + + Wprowadź swoje imie + Brak użytkowników. Proszę utworzyć nowego użytkownika w ustawieniach. + Nie można określić wartości + + Czy napewno chcesz usunąć wpis z bazy danych? + Czy napewno chcesz usunąć wszystkie wpisy z bazy danych? + Czy napewno chcesz usunąć użytkownika? + + Bluetooth + Wyszukaj wagę przy starcie + Wyszukuje wagi Bluetooth + Rodzaj urządzenia + + Label on data point + Point on data point + + Potwierdzenie usnięcia + + Przypomnienie + Dni tygodnia + Czas + Tekst powiadomienia + Pora by się zważyć + + Twój wzrost + Twój procent tkanki tłuszczowej + Twój procent wody organizmie + Twój procent masy mięśniowej + Twój obwód talii + Twój obwód bioder + na dzień + + Poniedziałek + Wtorek + Środa + Czwartek + Piątek + Sobota + Niedziela + urządzenie nie jest wspierane + Exportuj kopie zapasową + Importuj kopie zapasową + Kopia zapasowa + Katalog do eksportu + nie znaleziono + Ignoruj dane spoza zakresu + Waga początkowa + Oblicz średnią na dzień/miesiąc + Regression weight line + Regression polynom degree + Linia celu + + + Osiągnięto maksymalną ilość użytkowników wagi. + Proszę stanąć boso na wadze w celu przeprowadzenia pomiaru referencyjnego. + Mierzona waga: %.2f + + diff --git a/android_app/app/src/main/res/values-sk/strings.xml b/android_app/app/src/main/res/values-sk/strings.xml index ce156124..9a7b7292 100644 --- a/android_app/app/src/main/res/values-sk/strings.xml +++ b/android_app/app/src/main/res/values-sk/strings.xml @@ -19,7 +19,8 @@ Pridať používateľa ID Hmotnosť - BMI + Index telesnej hmotnosti (BMI) + Bazálny metabolický výdaj (BMR) Percento telesného tuku Percento vody Percento svalov @@ -28,6 +29,7 @@ Komentár Pomer pásu a výšky Pomer pásu a bokov + Hmotnosť kostí Chytré priradenie používateľa dni merania @@ -87,6 +89,7 @@ Spojenie úspešné nadviazané Inicializácia Bluetooth zariadenia Vyskytla neočakávaná chyba Bluetooth + Do %4$s boli pridané %1$.2f%2$s [%3$s] Zadajte vaše meno Žiadny používateľ. Prosím, vytvorte nového používateľa v nastaveniach. Nie je možné vypočítať hodnotu @@ -95,13 +98,13 @@ Naozaj chcete vymazať používateľa? Bluetooth Vyhľadať váhu po spustení - Názov zariadenia + Prebieha vyhľadávanie Bluetooth váhy Typ zariadenia Štítok na údajový bod Bod na údajový bod Potvrďte vymazanie Pripomienka - Pracovné dni + Dni v týždni Čas Text upozornenia Čas na váženie @@ -111,7 +114,7 @@ Vaše percento svalov v tele bolo Váš obvod pása bol Váš obvod bokov bol - do + v deň Pondelok Utorok Streda @@ -119,7 +122,7 @@ Piatok Sobota Nedeľa - Podporované budú + nepodporované zariadenie Export zálohy Import zálohy Zálohovanie @@ -129,7 +132,7 @@ Počiatočná hmotnosť Vypočítať priemer za deň/mesiac Vývoj úbytku hmotnosti - Radenie úbytku + Stupeň polynomiálnej regresie Cieľová línia Dosiahli ste maximálny počet viacerých používateľov. Prosím, postavte sa na váhu pre referenčné meranie. diff --git a/android_app/upload_apk.sh b/android_app/upload_apk.sh index 812eccab..36c65196 100644 --- a/android_app/upload_apk.sh +++ b/android_app/upload_apk.sh @@ -1,22 +1,2 @@ # copy apk file to home cp app/build/outputs/apk/app-debug.apk $HOME/openScale-dev-build.apk - - #go to home and setup git - cd $HOME - git config --global user.email "olie.xdev@googlemail.com" - git config --global user.name "oliexdev" - - #clone the repository - git clone --quiet --branch=master https://oliexdev:$GITHUB_API_KEY@github.com/oliexdev/openScale master > /dev/null - - #copy generated apk from build folder to repository - cp $HOME/openScale-dev-build.apk $HOME/master/openScale-dev-build.apk - - #go into repository - cd master - - #add, commit and push apk file - git add -f openScale-dev-build.apk - git commit -m "openScale dev build $TRAVIS_BUILD_NUMBER by Travis CI [skip ci]" openScale-dev-build.apk - git push -fq origin master > /dev/null - echo -e "Done\n" diff --git a/doc/excelvan_cf369ble/excelvan_cf369ble.jpg b/doc/excelvan_cf369ble/excelvan_cf369ble.jpg new file mode 100644 index 00000000..34d86161 Binary files /dev/null and b/doc/excelvan_cf369ble/excelvan_cf369ble.jpg differ diff --git a/openScale-dev-build.apk b/openScale-dev-build.apk deleted file mode 100644 index 51a0a70a..00000000 Binary files a/openScale-dev-build.apk and /dev/null differ