App 2.17.0: speed average, compact top bar, About in Settings
- "Speed, 5-min average" card under Speed: time-weighted mean speed, standing included, from the same samples as the other averages. - The top bar is one compact line (title and subtitle side by side). Version, update check and About moved from it to an App card on the Settings tab. - The Overview no longer scrolls in the car's window: checked on the emulator at 1778x640, the layout height the car reports, after trimming the page's padding and the tyre card's height. - The capacity hint says "Overview" instead of "Vehicle tab". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
This commit is contained in:
@@ -112,6 +112,10 @@ tyre pressures, GPS (lat, lon, elevation, heading) and the is_* flags. It does *
|
|||||||
INGEST_TOKEN) into git and pushed it. Commit amended and force-pushed; both values regenerated in
|
INGEST_TOKEN) into git and pushed it. Commit amended and force-pushed; both values regenerated in
|
||||||
the now gitignored `k8s/secrets.yaml` (since moved to `k8s/secrets/secrets.yaml`, outside
|
the now gitignored `k8s/secrets.yaml` (since moved to `k8s/secrets/secrets.yaml`, outside
|
||||||
`kubectl apply -f k8s/`). Filled-in secrets live only there from now on.
|
`kubectl apply -f k8s/`). Filled-in secrets live only there from now on.
|
||||||
|
- 2026-10-18 — App 2.17.0: "Speed, 5-min average" card under Speed. The top bar is one compact line
|
||||||
|
(title and subtitle); version, update check and About moved to an App card on the Settings tab.
|
||||||
|
The Overview fits the car's window without scrolling: checked on the emulator at 1778×640, the
|
||||||
|
layout height the car reports (less page padding, a lower tyre card).
|
||||||
- 2026-10-18 — App 2.16.4: drop-downs again, as Material exposed dropdown menus: their list leaves
|
- 2026-10-18 — App 2.16.4: drop-downs again, as Material exposed dropdown menus: their list leaves
|
||||||
the focus with the activity, so full screen stays (a Spinner's list is a focusable window of its
|
the focus with the activity, so full screen stays (a Spinner's list is a focusable window of its
|
||||||
own without the full-screen flags). 2.16.3 had replaced them with buttons.
|
own without the full-screen flags). 2.16.3 had replaced them with buttons.
|
||||||
|
|||||||
+2
-2
@@ -34,8 +34,8 @@ android {
|
|||||||
applicationId "com.stinnesbeck.nilsmg4"
|
applicationId "com.stinnesbeck.nilsmg4"
|
||||||
minSdk 27
|
minSdk 27
|
||||||
targetSdk 36
|
targetSdk 36
|
||||||
versionCode 88
|
versionCode 89
|
||||||
versionName "2.16.4"
|
versionName "2.17.0"
|
||||||
|
|
||||||
// Nothing about the server ships in the APK: its URL and ingest token are entered in
|
// Nothing about the server ships in the APK: its URL and ingest token are entered in
|
||||||
// the app's Server tab (ServerConfig), and the database is only reachable by the server.
|
// the app's Server tab (ServerConfig), and the database is only reachable by the server.
|
||||||
|
|||||||
@@ -94,7 +94,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
vehTireFl, vehTireFr, vehTireRl, vehTireRr,
|
vehTireFl, vehTireFr, vehTireRl, vehTireRr,
|
||||||
vehRangeTrip, vehRangeTripNote, vehRangeAverage, vehRangeAverageNote,
|
vehRangeTrip, vehRangeTripNote, vehRangeAverage, vehRangeAverageNote,
|
||||||
vehUsageTrip, vehUsageTripNote, vehUsageAverage, vehUsageAverageNote,
|
vehUsageTrip, vehUsageTripNote, vehUsageAverage, vehUsageAverageNote,
|
||||||
vehEnergyTrip, vehEnergyTripNote, vehPowerAverage, vehPowerAverageNote;
|
vehEnergyTrip, vehEnergyTripNote, vehPowerAverage, vehPowerAverageNote,
|
||||||
|
vehSpeedAverage, vehSpeedAverageNote;
|
||||||
|
|
||||||
/** Usable pack capacity for the range estimates; the car does not publish it. */
|
/** Usable pack capacity for the range estimates; the car does not publish it. */
|
||||||
static final String USABLE_KWH_KEY = "usable_kwh";
|
static final String USABLE_KWH_KEY = "usable_kwh";
|
||||||
@@ -233,7 +234,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
getTheme().applyStyle(AccentColor.fromPref(prefs.getString(AccentColor.PREF_KEY, null)).overlay, true);
|
getTheme().applyStyle(AccentColor.fromPref(prefs.getString(AccentColor.PREF_KEY, null)).overlay, true);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
((TextView) findViewById(R.id.version_badge)).setText("v" + BuildConfig.VERSION_NAME);
|
|
||||||
|
|
||||||
|
|
||||||
// The pages are inflated here, once, and handed to the pager as fixed,
|
// The pages are inflated here, once, and handed to the pager as fixed,
|
||||||
@@ -277,8 +277,10 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
((ViewPager2) findViewById(R.id.content)).setCurrentItem(savedInstanceState.getInt(STATE_PAGE, 0), false);
|
((ViewPager2) findViewById(R.id.content)).setCurrentItem(savedInstanceState.getInt(STATE_PAGE, 0), false);
|
||||||
}
|
}
|
||||||
findViewById(R.id.about_button).setOnClickListener(v -> showAbout());
|
((TextView) settingsPane.findViewById(R.id.settings_version))
|
||||||
findViewById(R.id.update_button).setOnClickListener(v -> checkForUpdate(v));
|
.setText(getString(R.string.settings_version, BuildConfig.VERSION_NAME));
|
||||||
|
settingsPane.findViewById(R.id.settings_about_button).setOnClickListener(v -> showAbout());
|
||||||
|
settingsPane.findViewById(R.id.settings_update_button).setOnClickListener(v -> checkForUpdate(v));
|
||||||
|
|
||||||
// Unstable builds check for a newer pre-release; the stable flavor's UpdateHook is
|
// Unstable builds check for a newer pre-release; the stable flavor's UpdateHook is
|
||||||
// a no-op and does not even contain the updater.
|
// a no-op and does not even contain the updater.
|
||||||
@@ -1288,6 +1290,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
vehEnergyTripNote = vehiclePane.findViewById(R.id.vehicle_energy_trip_note);
|
vehEnergyTripNote = vehiclePane.findViewById(R.id.vehicle_energy_trip_note);
|
||||||
vehPowerAverage = vehiclePane.findViewById(R.id.vehicle_power_average);
|
vehPowerAverage = vehiclePane.findViewById(R.id.vehicle_power_average);
|
||||||
vehPowerAverageNote = vehiclePane.findViewById(R.id.vehicle_power_average_note);
|
vehPowerAverageNote = vehiclePane.findViewById(R.id.vehicle_power_average_note);
|
||||||
|
vehSpeedAverage = vehiclePane.findViewById(R.id.vehicle_speed_average);
|
||||||
|
vehSpeedAverageNote = vehiclePane.findViewById(R.id.vehicle_speed_average_note);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double usableKwh() {
|
private double usableKwh() {
|
||||||
@@ -1308,6 +1312,9 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
Double power = estimator.averagePowerKw(monotonicMs);
|
Double power = estimator.averagePowerKw(monotonicMs);
|
||||||
vehPowerAverage.setText(power == null ? "—" : getString(R.string.power_kw, power));
|
vehPowerAverage.setText(power == null ? "—" : getString(R.string.power_kw, power));
|
||||||
vehPowerAverageNote.setText(power == null ? R.string.power_waiting : R.string.usage_last_5_min);
|
vehPowerAverageNote.setText(power == null ? R.string.power_waiting : R.string.usage_last_5_min);
|
||||||
|
Double speed = estimator.averageSpeedKmh(monotonicMs);
|
||||||
|
vehSpeedAverage.setText(speed == null ? "—" : getString(R.string.speed_kmh, speed));
|
||||||
|
vehSpeedAverageNote.setText(speed == null ? R.string.power_waiting : R.string.usage_last_5_min);
|
||||||
Double energy = estimator.energySinceStart();
|
Double energy = estimator.energySinceStart();
|
||||||
vehEnergyTrip.setText(energy == null ? "—" : getString(R.string.energy_kwh, energy));
|
vehEnergyTrip.setText(energy == null ? "—" : getString(R.string.energy_kwh, energy));
|
||||||
vehEnergyTripNote.setText(energy == null ? R.string.energy_trip_waiting : R.string.energy_trip_note);
|
vehEnergyTripNote.setText(energy == null ? R.string.energy_trip_waiting : R.string.energy_trip_note);
|
||||||
|
|||||||
@@ -177,6 +177,26 @@ final class RangeEstimator {
|
|||||||
return energyKwh / (covered / 3_600_000.0);
|
return energyKwh / (covered / 3_600_000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Mean speed over the last five minutes, time-weighted, standing included; null below a minute. */
|
||||||
|
synchronized Double averageSpeedKmh(long nowMs) {
|
||||||
|
double distanceKm = 0;
|
||||||
|
long covered = 0;
|
||||||
|
Sample previous = null;
|
||||||
|
for (Sample s : samples) {
|
||||||
|
if (s.timeMs < nowMs - WINDOW_MS) continue;
|
||||||
|
if (previous != null) {
|
||||||
|
long dt = s.timeMs - previous.timeMs;
|
||||||
|
if (dt > 0 && dt <= MAX_GAP_MS) {
|
||||||
|
distanceKm += (previous.speedKmh + s.speedKmh) / 2 * (dt / 3_600_000.0);
|
||||||
|
covered += dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previous = s;
|
||||||
|
}
|
||||||
|
if (covered < MIN_WINDOW_MS) return null;
|
||||||
|
return distanceKm / (covered / 3_600_000.0);
|
||||||
|
}
|
||||||
|
|
||||||
synchronized void clear() {
|
synchronized void clear() {
|
||||||
samples.clear();
|
samples.clear();
|
||||||
tripEnergyKwh = 0;
|
tripEnergyKwh = 0;
|
||||||
|
|||||||
@@ -16,14 +16,11 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:orientation="vertical">
|
<LinearLayout android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:orientation="vertical">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:paddingStart="24dp" android:paddingEnd="24dp" android:paddingTop="16dp" android:paddingBottom="8dp">
|
<!-- One compact line: the Overview has to fit the car's 1778×720 px window (about 640 dp for
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical">
|
layouts). Version, update check and About are on the Settings tab. -->
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_overview_title" android:textAppearance="@style/Text.EV.Title" android:id="@+id/header_title" android:textSize="32sp" />
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:baselineAligned="true" android:paddingStart="24dp" android:paddingEnd="24dp" android:paddingTop="10dp" android:paddingBottom="2dp">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_overview_subtitle" android:textAppearance="@style/Text.EV.Secondary" android:id="@+id/header_subtitle" android:layout_marginTop="6dp" />
|
<TextView android:id="@+id/header_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/design_overview_title" android:textAppearance="@style/Text.EV.Title" android:textSize="24sp" android:maxLines="1" />
|
||||||
</LinearLayout>
|
<TextView android:id="@+id/header_subtitle" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:text="@string/design_overview_subtitle" android:textAppearance="@style/Text.EV.Secondary" android:maxLines="1" android:ellipsize="end" />
|
||||||
<TextView android:id="@+id/version_badge" style="@style/Text.EV.VersionBadge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" />
|
|
||||||
<com.google.android.material.button.MaterialButton android:id="@+id/update_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="72dp" android:layout_height="72dp" android:minWidth="0dp" android:padding="0dp" android:contentDescription="@string/update_check" app:icon="@drawable/ic_refresh" app:iconGravity="textStart" app:iconPadding="0dp" app:iconTint="?attr/evAccent" />
|
|
||||||
<com.google.android.material.button.MaterialButton android:id="@+id/about_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="72dp" android:layout_height="72dp" android:layout_marginStart="8dp" android:minWidth="0dp" android:padding="0dp" android:contentDescription="@string/about_action" app:icon="@drawable/ic_info" app:iconGravity="textStart" app:iconPadding="0dp" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />
|
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -53,6 +53,12 @@
|
|||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_saved_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_saved_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<TextView android:id="@+id/wifi_saved_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:textAppearance="@style/Text.EV.Body" android:lineSpacingExtra="16dp" />
|
<TextView android:id="@+id/wifi_saved_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:textAppearance="@style/Text.EV.Body" android:lineSpacingExtra="16dp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_app_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
|
<TextView android:id="@+id/settings_version" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:textAppearance="@style/Text.EV.Body" />
|
||||||
|
<com.google.android.material.button.MaterialButton android:id="@+id/settings_update_button" style="@style/Widget.EV.Button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="@string/btn_check_update" app:icon="@drawable/ic_refresh" />
|
||||||
|
<com.google.android.material.button.MaterialButton android:id="@+id/settings_about_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/btn_about" app:icon="@drawable/ic_info" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</com.evsuite.abrp.StableScrollView>
|
</com.evsuite.abrp.StableScrollView>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<com.evsuite.abrp.StableScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:clipToPadding="false">
|
<com.evsuite.abrp.StableScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:clipToPadding="false">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingStart="24dp" android:paddingEnd="24dp" android:paddingTop="12dp" android:paddingBottom="12dp">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:baselineAligned="false">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:baselineAligned="false">
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:orientation="vertical" android:minHeight="112dp" android:padding="16dp" android:background="@drawable/bg_battery_card" android:layout_weight="1" android:layout_marginEnd="10dp">
|
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:orientation="vertical" android:minHeight="112dp" android:padding="16dp" android:background="@drawable/bg_battery_card" android:layout_weight="1" android:layout_marginEnd="10dp">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_battery_short" android:textAppearance="@style/Text.EV.Secondary" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_battery_short" android:textAppearance="@style/Text.EV.Secondary" />
|
||||||
@@ -52,7 +52,11 @@
|
|||||||
<TextView android:id="@+id/vehicle_power_average" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:layout_marginTop="6dp" android:textAppearance="@style/Text.EV.Metric.Compact" android:gravity="end" android:fontFeatureSettings="tnum" android:maxLines="1" android:autoSizeTextType="uniform" android:autoSizeMinTextSize="18sp" android:autoSizeMaxTextSize="28sp" android:autoSizeStepGranularity="1sp" />
|
<TextView android:id="@+id/vehicle_power_average" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:layout_marginTop="6dp" android:textAppearance="@style/Text.EV.Metric.Compact" android:gravity="end" android:fontFeatureSettings="tnum" android:maxLines="1" android:autoSizeTextType="uniform" android:autoSizeMinTextSize="18sp" android:autoSizeMaxTextSize="28sp" android:autoSizeStepGranularity="1sp" />
|
||||||
<TextView android:id="@+id/vehicle_power_average_note" android:gravity="end" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textAppearance="@style/Text.EV.Secondary" android:textColor="?attr/evAccentLight" android:textSize="16sp" android:maxLines="1" android:ellipsize="end" />
|
<TextView android:id="@+id/vehicle_power_average_note" android:gravity="end" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textAppearance="@style/Text.EV.Secondary" android:textColor="?attr/evAccentLight" android:textSize="16sp" android:maxLines="1" android:ellipsize="end" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<Space android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" android:layout_marginEnd="10dp" />
|
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginEnd="10dp" android:orientation="vertical" android:minHeight="112dp" android:padding="16dp" android:background="@drawable/bg_glass">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/vehicle_row_speed_average" android:textAppearance="@style/Text.EV.Secondary" />
|
||||||
|
<TextView android:id="@+id/vehicle_speed_average" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:layout_marginTop="6dp" android:textAppearance="@style/Text.EV.Metric.Compact" android:gravity="end" android:fontFeatureSettings="tnum" android:maxLines="1" android:autoSizeTextType="uniform" android:autoSizeMinTextSize="18sp" android:autoSizeMaxTextSize="28sp" android:autoSizeStepGranularity="1sp" />
|
||||||
|
<TextView android:id="@+id/vehicle_speed_average_note" android:gravity="end" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textAppearance="@style/Text.EV.Secondary" android:textColor="?attr/evAccentLight" android:textSize="16sp" android:maxLines="1" android:ellipsize="end" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<Space android:layout_width="1dp" android:layout_height="16dp" />
|
<Space android:layout_width="1dp" android:layout_height="16dp" />
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:baselineAligned="false">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:baselineAligned="false">
|
||||||
@@ -71,7 +75,7 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:padding="20dp" android:background="@drawable/bg_glass">
|
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:padding="20dp" android:background="@drawable/bg_glass">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_tires" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_tires" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="224dp" android:orientation="horizontal" android:gravity="center_vertical">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="196dp" android:orientation="horizontal" android:gravity="center_vertical">
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/vehicle_tire_fl" android:textAppearance="@style/Text.EV.Secondary" android:gravity="center" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/vehicle_tire_fl" android:textAppearance="@style/Text.EV.Secondary" android:gravity="center" />
|
||||||
<TextView android:id="@+id/vehicle_tire_fl" android:fontFeatureSettings="tnum" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Body" android:gravity="center" android:layout_marginTop="8dp" android:textColor="?attr/evAccentLight" />
|
<TextView android:id="@+id/vehicle_tire_fl" android:fontFeatureSettings="tnum" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Body" android:gravity="center" android:layout_marginTop="8dp" android:textColor="?attr/evAccentLight" />
|
||||||
|
|||||||
@@ -2,14 +2,11 @@
|
|||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/app_root" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:background="@color/ev_background">
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/app_root" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:background="@color/ev_background">
|
||||||
<com.evsuite.abrp.PremiumBackdropView android:layout_width="match_parent" android:layout_height="match_parent"/>
|
<com.evsuite.abrp.PremiumBackdropView android:layout_width="match_parent" android:layout_height="match_parent"/>
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:paddingStart="24dp" android:paddingEnd="24dp" android:paddingTop="16dp" android:paddingBottom="8dp">
|
<!-- One compact line: the Overview has to fit the car's 1778×720 px window (about 640 dp for
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical">
|
layouts). Version, update check and About are on the Settings tab. -->
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_overview_title" android:textAppearance="@style/Text.EV.Title" android:id="@+id/header_title" android:textSize="24sp"/>
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_vertical" android:baselineAligned="true" android:paddingStart="24dp" android:paddingEnd="24dp" android:paddingTop="10dp" android:paddingBottom="2dp">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_overview_subtitle" android:textAppearance="@style/Text.EV.Secondary" android:id="@+id/header_subtitle" android:layout_marginTop="6dp"/>
|
<TextView android:id="@+id/header_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/design_overview_title" android:textAppearance="@style/Text.EV.Title" android:textSize="24sp" android:maxLines="1" />
|
||||||
</LinearLayout>
|
<TextView android:id="@+id/header_subtitle" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:text="@string/design_overview_subtitle" android:textAppearance="@style/Text.EV.Secondary" android:maxLines="1" android:ellipsize="end" />
|
||||||
<TextView android:id="@+id/version_badge" style="@style/Text.EV.VersionBadge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp"/>
|
|
||||||
<com.google.android.material.button.MaterialButton android:id="@+id/update_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="72dp" android:layout_height="72dp" android:minWidth="0dp" android:padding="0dp" android:contentDescription="@string/update_check" app:icon="@drawable/ic_refresh" app:iconGravity="textStart" app:iconPadding="0dp" app:iconTint="?attr/evAccent"/>
|
|
||||||
<com.google.android.material.button.MaterialButton android:id="@+id/about_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="72dp" android:layout_height="72dp" android:layout_marginStart="8dp" android:minWidth="0dp" android:padding="0dp" android:contentDescription="@string/about_action" app:icon="@drawable/ic_info" app:iconGravity="textStart" app:iconPadding="0dp"/>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/>
|
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/>
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="8dp" android:background="@drawable/bg_sidebar">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="8dp" android:background="@drawable/bg_sidebar">
|
||||||
|
|||||||
@@ -50,5 +50,11 @@
|
|||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_saved_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/wifi_saved_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<TextView android:id="@+id/wifi_saved_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:textAppearance="@style/Text.EV.Body" android:lineSpacingExtra="16dp" />
|
<TextView android:id="@+id/wifi_saved_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:textAppearance="@style/Text.EV.Body" android:lineSpacingExtra="16dp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_app_title" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
|
<TextView android:id="@+id/settings_version" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:textAppearance="@style/Text.EV.Body" />
|
||||||
|
<com.google.android.material.button.MaterialButton android:id="@+id/settings_update_button" style="@style/Widget.EV.Button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="@string/btn_check_update" app:icon="@drawable/ic_refresh" />
|
||||||
|
<com.google.android.material.button.MaterialButton android:id="@+id/settings_about_button" style="@style/Widget.EV.Button.Outlined" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/btn_about" app:icon="@drawable/ic_info" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</com.evsuite.abrp.StableScrollView>
|
</com.evsuite.abrp.StableScrollView>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<com.evsuite.abrp.StableScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:clipToPadding="false">
|
<com.evsuite.abrp.StableScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:clipToPadding="false">
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="24dp">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingStart="24dp" android:paddingEnd="24dp" android:paddingTop="12dp" android:paddingBottom="12dp">
|
||||||
<GridLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:columnCount="2">
|
<GridLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:columnCount="2">
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:orientation="vertical" android:minHeight="112dp" android:padding="16dp" android:background="@drawable/bg_battery_card" android:layout_columnWeight="1" android:layout_margin="4dp">
|
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:orientation="vertical" android:minHeight="112dp" android:padding="16dp" android:background="@drawable/bg_battery_card" android:layout_columnWeight="1" android:layout_margin="4dp">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_battery_short" android:textAppearance="@style/Text.EV.Secondary" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_battery_short" android:textAppearance="@style/Text.EV.Secondary" />
|
||||||
@@ -49,6 +49,11 @@
|
|||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/vehicle_row_speed" android:textAppearance="@style/Text.EV.Secondary" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/vehicle_row_speed" android:textAppearance="@style/Text.EV.Secondary" />
|
||||||
<TextView android:id="@+id/vehicle_speed" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:layout_marginTop="6dp" android:textAppearance="@style/Text.EV.Metric.Compact" android:gravity="end" android:fontFeatureSettings="tnum" android:maxLines="1" android:autoSizeTextType="uniform" android:autoSizeMinTextSize="18sp" android:autoSizeMaxTextSize="28sp" android:autoSizeStepGranularity="1sp" />
|
<TextView android:id="@+id/vehicle_speed" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:layout_marginTop="6dp" android:textAppearance="@style/Text.EV.Metric.Compact" android:gravity="end" android:fontFeatureSettings="tnum" android:maxLines="1" android:autoSizeTextType="uniform" android:autoSizeMinTextSize="18sp" android:autoSizeMaxTextSize="28sp" android:autoSizeStepGranularity="1sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_columnWeight="1" android:layout_margin="4dp" android:orientation="vertical" android:minHeight="112dp" android:padding="16dp" android:background="@drawable/bg_glass">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/vehicle_row_speed_average" android:textAppearance="@style/Text.EV.Secondary" />
|
||||||
|
<TextView android:id="@+id/vehicle_speed_average" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:layout_marginTop="6dp" android:textAppearance="@style/Text.EV.Metric.Compact" android:gravity="end" android:fontFeatureSettings="tnum" android:maxLines="1" android:autoSizeTextType="uniform" android:autoSizeMinTextSize="18sp" android:autoSizeMaxTextSize="28sp" android:autoSizeStepGranularity="1sp" />
|
||||||
|
<TextView android:id="@+id/vehicle_speed_average_note" android:gravity="end" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textAppearance="@style/Text.EV.Secondary" android:textColor="?attr/evAccentLight" android:textSize="16sp" android:maxLines="1" android:ellipsize="end" />
|
||||||
|
</LinearLayout>
|
||||||
</GridLayout>
|
</GridLayout>
|
||||||
<Space android:layout_width="1dp" android:layout_height="16dp" />
|
<Space android:layout_width="1dp" android:layout_height="16dp" />
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="20dp" android:background="@drawable/bg_glass">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="20dp" android:background="@drawable/bg_glass">
|
||||||
@@ -66,7 +71,7 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="20dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="20dp" android:background="@drawable/bg_glass" android:layout_marginTop="16dp">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_tires" android:textAppearance="@style/Text.EV.Eyebrow" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/design_tires" android:textAppearance="@style/Text.EV.Eyebrow" />
|
||||||
<LinearLayout android:layout_width="match_parent" android:layout_height="224dp" android:orientation="horizontal" android:gravity="center_vertical">
|
<LinearLayout android:layout_width="match_parent" android:layout_height="196dp" android:orientation="horizontal" android:gravity="center_vertical">
|
||||||
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
||||||
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/vehicle_tire_fl" android:textAppearance="@style/Text.EV.Secondary" android:gravity="center" />
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/vehicle_tire_fl" android:textAppearance="@style/Text.EV.Secondary" android:gravity="center" />
|
||||||
<TextView android:id="@+id/vehicle_tire_fl" android:fontFeatureSettings="tnum" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Body" android:gravity="center" android:layout_marginTop="8dp" android:textColor="?attr/evAccentLight" />
|
<TextView android:id="@+id/vehicle_tire_fl" android:fontFeatureSettings="tnum" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/no_value" android:textAppearance="@style/Text.EV.Body" android:gravity="center" android:layout_marginTop="8dp" android:textColor="?attr/evAccentLight" />
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
<string name="usage_last_5_min">over the last 5 minutes</string>
|
<string name="usage_last_5_min">over the last 5 minutes</string>
|
||||||
<string name="hint_usable_capacity">Usable battery capacity</string>
|
<string name="hint_usable_capacity">Usable battery capacity</string>
|
||||||
<string name="btn_save_capacity">Save capacity</string>
|
<string name="btn_save_capacity">Save capacity</string>
|
||||||
<string name="helper_usable_capacity">Used for the range estimates on the Vehicle tab. The 51 kWh MG4 battery has 50.8 kWh usable, the 64 kWh one 61.7, the 77 kWh one 74.4.</string>
|
<string name="helper_usable_capacity">Used for the range estimates on the Overview. The 51 kWh MG4 battery has 50.8 kWh usable, the 64 kWh one 61.7, the 77 kWh one 74.4.</string>
|
||||||
<string name="usable_capacity_saved">Usable capacity saved</string>
|
<string name="usable_capacity_saved">Usable capacity saved</string>
|
||||||
<string name="usable_capacity_invalid">Enter a value between 10 and 150 kWh</string>
|
<string name="usable_capacity_invalid">Enter a value between 10 and 150 kWh</string>
|
||||||
<string name="vehicle_row_speed">Speed</string>
|
<string name="vehicle_row_speed">Speed</string>
|
||||||
@@ -204,6 +204,11 @@
|
|||||||
<string name="update_check">Check for updates</string>
|
<string name="update_check">Check for updates</string>
|
||||||
<string name="update_checking">Checking for a new OTA version…</string>
|
<string name="update_checking">Checking for a new OTA version…</string>
|
||||||
<string name="update_dialog_title">Software update</string>
|
<string name="update_dialog_title">Software update</string>
|
||||||
|
<string name="btn_check_update">Check for updates</string>
|
||||||
|
<string name="btn_about">About Nils\' MG4</string>
|
||||||
|
<string name="settings_version">Version %1$s</string>
|
||||||
|
<string name="vehicle_row_speed_average">Speed, 5-min average</string>
|
||||||
|
<string name="speed_kmh">%1$.0f km/h</string>
|
||||||
<string name="update_downloading">Downloading and verifying…</string>
|
<string name="update_downloading">Downloading and verifying…</string>
|
||||||
<string name="update_downloading_percent">Downloading… %1$d%%</string>
|
<string name="update_downloading_percent">Downloading… %1$d%%</string>
|
||||||
<string name="about_action">About</string>
|
<string name="about_action">About</string>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<string name="design_service_title">Live data.</string>
|
<string name="design_service_title">Live data.</string>
|
||||||
<string name="design_service_subtitle">Where your car\'s live data goes, and how often.</string>
|
<string name="design_service_subtitle">Where your car\'s live data goes, and how often.</string>
|
||||||
<string name="design_settings_title">Settings.</string>
|
<string name="design_settings_title">Settings.</string>
|
||||||
<string name="design_settings_subtitle">Display, battery, charging price and Wi-Fi.</string>
|
<string name="design_settings_subtitle">Display, battery, charging price, Wi-Fi and updates.</string>
|
||||||
<string name="design_log_title">Every upload, right here.</string>
|
<string name="design_log_title">Every upload, right here.</string>
|
||||||
<string name="design_log_subtitle">Status and details of recent uploads.</string>
|
<string name="design_log_subtitle">Status and details of recent uploads.</string>
|
||||||
<string name="design_battery">BATTERY</string>
|
<string name="design_battery">BATTERY</string>
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
<string name="design_abrp_title">ABRP, DIRECTLY FROM THE CAR</string>
|
<string name="design_abrp_title">ABRP, DIRECTLY FROM THE CAR</string>
|
||||||
<string name="design_display_title">DISPLAY AND STEERING WHEEL</string>
|
<string name="design_display_title">DISPLAY AND STEERING WHEEL</string>
|
||||||
<string name="design_battery_settings_title">BATTERY</string>
|
<string name="design_battery_settings_title">BATTERY</string>
|
||||||
|
<string name="design_app_title">APP</string>
|
||||||
<string name="design_price_title">CHARGING PRICE</string>
|
<string name="design_price_title">CHARGING PRICE</string>
|
||||||
<string name="design_service_timing">UPDATE FREQUENCY</string>
|
<string name="design_service_timing">UPDATE FREQUENCY</string>
|
||||||
<string name="design_car_desc">Tire pressure positions on the vehicle</string>
|
<string name="design_car_desc">Tire pressure positions on the vehicle</string>
|
||||||
|
|||||||
@@ -140,4 +140,16 @@ public class RangeEstimatorTest {
|
|||||||
for (long t = 315_000; t <= 450_000; t += 15_000) r.add(t, 2f, 0f);
|
for (long t = 315_000; t <= 450_000; t += 15_000) r.add(t, 2f, 0f);
|
||||||
assertEquals(11.0, r.averagePowerKw(450_000), 1.0);
|
assertEquals(11.0, r.averagePowerKw(450_000), 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void averageSpeedOverTheLastFiveMinutes() {
|
||||||
|
RangeEstimator r = new RangeEstimator();
|
||||||
|
r.add(0, 10f, 60f);
|
||||||
|
assertNull(r.averageSpeedKmh(0));
|
||||||
|
for (long t = 15_000; t <= 300_000; t += 15_000) r.add(t, 10f, 60f);
|
||||||
|
assertEquals(60.0, r.averageSpeedKmh(300_000), 1e-6);
|
||||||
|
// Half the window standing at lights halves the average.
|
||||||
|
for (long t = 315_000; t <= 450_000; t += 15_000) r.add(t, 1f, 0f);
|
||||||
|
assertEquals(30.0, r.averageSpeedKmh(450_000), 4.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user