add settings to example 'wear-os-gps'

This commit is contained in:
pls.153 2022-07-05 17:59:16 +02:00
parent de50d90245
commit f1a7d0093c
13 changed files with 174 additions and 36 deletions

View file

@ -20,6 +20,10 @@ and adding to resources included in the executable).
So, you only need to **manually** care about the usual ASDF project files in
`app.asd`.
But -- *of course* -- you still need to run the respective **qmake** command
every time you add new files to the project, because the automation is all
defined in `app.pro`.
Run desktop
-----------

View file

@ -4,14 +4,15 @@
QT_BEGIN_NAMESPACE
QVariant QT::keepScreenOn() {
QtAndroid::runOnAndroidThread([] {
QVariant QT::keepScreenOn(const QVariant& on) {
QtAndroid::runOnAndroidThread([&] {
QAndroidJniObject activity = QtAndroid::androidActivity();
if (activity.isValid()) {
QAndroidJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
if (window.isValid()) {
const int FLAG_KEEP_SCREEN_ON = 128;
window.callMethod<void>("addFlags", "(I)V", FLAG_KEEP_SCREEN_ON);
const char* method = on.toBool() ? "addFlags" : "clearFlags";
window.callMethod<void>(method, "(I)V", FLAG_KEEP_SCREEN_ON);
}
}
QAndroidJniEnvironment env;

View file

@ -11,7 +11,7 @@ class QT : public QObject {
Q_OBJECT
public:
Q_INVOKABLE QVariant keepScreenOn();
Q_INVOKABLE QVariant keepScreenOn(const QVariant& = true);
};
QT_END_NAMESPACE

View file

@ -8,8 +8,9 @@
(qt:ini)
#+android
(progn
(qt:keep-screen-on qt:*cpp*)
(ensure-permissions :access-fine-location)))
(qlater (lambda () (qt:keep-screen-on qt:*cpp*))) ; delay until UI is loaded (see 'Settings.qml')
(ensure-permissions :access-fine-location))
(q> |ready| ui:*position-source* t))
(defun closing ()
(close *log-stream*)
@ -64,4 +65,12 @@
(round* (speed*) 1)
(round* (distance))))))
(defun always-on-changed (on) ; called from QML
#+android
(qt:keep-screen-on qt:*cpp* on))
(defun set-max-speed () ; called from QML
(q> |maximumValue| ui:*speed*
(q< |value| ui:*max-speed*)))
(qlater 'run)

View file

@ -1,14 +1,16 @@
(in-package :gps)
(defvar *distance-samples* 5)
(let ((speed 0.0)
samples)
(defun update-speed ()
"After 10 distance samples, calculate average speed and update on every new
distance sample."
"After *DISTANCE-SAMPLES* samples, calculate average speed and update on
every new distance sample."
(push (cons (distance)
(get-internal-real-time))
samples)
(when (> (length samples) 10)
(when (> (length samples) *distance-samples*)
(setf samples (butlast samples))
(let ((b (first samples))
(a (first (last samples))))

View file

@ -3,10 +3,14 @@
(:export
#:*accuracy*
#:*distance*
#:*max-speed*
#:*position-source*
#:*speed*))
(in-package :ui)
(defparameter *accuracy* "accuracy")
(defparameter *distance* "distance")
(defparameter *max-speed* "max_speed")
(defparameter *position-source* "position_source")
(defparameter *speed* "speed")

View file

@ -8,11 +8,11 @@ Rectangle {
color: "black"
CircularGauge {
id: gauge
id: speed
objectName: "speed"
anchors.fill: parent
maximumValue: 10
stepSize: 0.1
stepSize: 0.05
Behavior on value {
NumberAnimation {
@ -23,8 +23,8 @@ Rectangle {
style: CircularGaugeStyle {
id: style
labelStepSize: 1
tickmarkStepSize: 1
labelStepSize: parent.maximumValue / 10
tickmarkStepSize: labelStepSize
minorTickmarkCount: 5
minimumValueAngle: -90
maximumValueAngle: 90
@ -43,7 +43,7 @@ Rectangle {
ctx.strokeStyle = limitColor
ctx.lineWidth = outerRadius * 0.02
ctx.arc(outerRadius, outerRadius, outerRadius - ctx.lineWidth / 2,
toRad(valueToAngle(limit) - 90), toRad(valueToAngle(gauge.maximumValue) - 90))
toRad(valueToAngle(limit) - 90), toRad(valueToAngle(speed.maximumValue) - 90))
ctx.stroke()
}
}

View file

@ -0,0 +1,19 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import "." as Ext
Rectangle {
color: "black"
Ext.Gauge {}
Column {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
spacing: -5
Ext.LogText { objectName: "distance"; font.pixelSize: 48 }
Ext.LogText { objectName: "accuracy"; font.pixelSize: 24 }
}
}

View file

@ -0,0 +1,46 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle {
Column {
anchors.centerIn: parent
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: "max speed"
font.pixelSize: 16
font.weight: Font.DemiBold
}
Tumbler {
id: maxSpeed
objectName: "max_speed"
anchors.horizontalCenter: parent.horizontalCenter
height: 80
model: [10, 20, 30, 40, 50]
visibleItemCount: 3
property int value: model[0]
delegate: Text {
text: modelData
font.pixelSize: 22
font.bold: true
opacity: 0.4 + Math.max(0, 1 - Math.abs(Tumbler.displacement)) * 0.6
Component.onCompleted: { maxSpeed.width = paintedWidth }
}
onCurrentIndexChanged: { value = model[currentIndex] }
}
Switch {
objectName: "always_on"
text: "always on"
font.pixelSize: 16
font.weight: Font.DemiBold
checked: true
onCheckedChanged: Lisp.call("gps:always-on-changed", checked)
}
}
}

View file

@ -14,7 +14,10 @@ Rectangle {
updateInterval: 1000
active: true
property bool ready: false
onPositionChanged: {
if (ready) {
Lisp.call("gps:position-changed",
position.latitudeValid ? position.coordinate.latitude : null,
position.longitudeValid ? position.coordinate.longitude : null,
@ -24,17 +27,38 @@ Rectangle {
position.timestamp.toLocaleString(Qt.locale(), "yyyy-MM-dd hh:mm:ss"))
}
}
}
Ext.Gauge {}
SwipeView {
id: view
anchors.fill: parent
orientation: Qt.Vertical
Column {
onCurrentIndexChanged: {
if (currentIndex === 0) {
Lisp.call("gps:set-max-speed")
}
}
Ext.MainView {}
Ext.Settings {}
}
PageIndicator {
id: indicator
anchors.bottom: view.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
spacing: -5
height: 14
count: view.count
currentIndex: view.currentIndex
Ext.LogText { objectName: "distance"; font.pixelSize: 48 }
Ext.LogText { objectName: "accuracy"; font.pixelSize: 24 }
delegate: Rectangle {
implicitWidth: 6
implicitHeight: 6
radius: width / 2
color: "white"
opacity: index === indicator.currentIndex ? 1 : 0.35
}
}
// quit

View file

@ -7,6 +7,18 @@ requires WearOS 2 or later.
It is assumed that you already enabled the developer settings on your watch.
--
Every Lisp file under `lisp/` and every qml/image/font/whatever file under
`qml/` is added **automatically** to your Qt project file (both for re-compile
and adding to resources included in the executable).
So, you only need to **manually** care about the usual ASDF project files in
`app.asd`.
But -- *of course* -- you still need to run the respective **qmake** command
every time you add new files to the project, because the automation is all
defined in `app.pro`.
Build 32bit android APK
@ -27,7 +39,7 @@ Now you can build the app:
```
$ cd build-android
$ qmake-android "CONFIG+=32bit" ..
$ qmake-android .. # "CONFIG+=32bit" can be omitted here: already defined in app.pro
$ make apk
$ ./install-run.sh

View file

@ -14,7 +14,12 @@ Info
This is a practical example of displaying both the speed and the whole distance
of e.g. a canoe session (only meant for constant altitude values). You probably
need to adapt the maximum speed value (km/h) to your personal needs.
need to adapt the maximum speed value (km/h) to your personal needs, see
settings (swipe up).
An important feature is keeping the display always on (implemented with the Qt
JNI interface). But this also consumes more battery, so you can switch it off
in the settings.
The data is automatically logged, and can be accessed with e.g.
**Device File Explorer** from Android Studio (see Help / Find Action...).
@ -35,8 +40,8 @@ using **Google Earth** (the free desktop app).
A simple **Kalman** filter is used for the necessary GPS data smoothing.
The UI uses a `CircularGauge` for displaying the speed (an average of the
latest 10 seconds). Additionally it shows the whole distance and the GPS
The UI uses a `CircularGauge` for displaying the speed (by default, an average
of the latest 5 seconds). Additionally it shows the whole distance and the GPS
accuracy in meters.

View file

@ -10,6 +10,18 @@ You'll also need an easy to apply hack for the **heart rate sensor**, see
It is assumed that you already enabled the developer settings on your watch.
--
Every Lisp file under `lisp/` and every qml/image/font/whatever file under
`qml/` is added **automatically** to your Qt project file (both for re-compile
and adding to resources included in the executable).
So, you only need to **manually** care about the usual ASDF project files in
`app.asd`.
But -- *of course* -- you still need to run the respective **qmake** command
every time you add new files to the project, because the automation is all
defined in `app.pro`.
Build 32bit android APK
@ -30,7 +42,7 @@ Now you can build the app:
```
$ cd build-android
$ qmake-android "CONFIG+=32bit" ..
$ qmake-android .. # "CONFIG+=32bit" can be omitted here: already defined in app.pro
$ make apk
$ ./install-run.sh