initial commit
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
|||||||
|
# CMake build directories
|
||||||
|
build/
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# CMake generated files
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles/
|
||||||
|
cmake_install.cmake
|
||||||
|
Makefile
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
|
# Qt generated files
|
||||||
|
.qmlcache/
|
||||||
|
.qtc_clangd/
|
||||||
|
*.qmlc
|
||||||
|
*.jsc
|
||||||
|
|
||||||
|
# IDE/editor junk
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.user
|
||||||
|
*.user.*
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
project(bottomdash VERSION 0.1 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Quick)
|
||||||
|
|
||||||
|
qt_standard_project_setup(REQUIRES 6.8)
|
||||||
|
|
||||||
|
qt_add_executable(bottomdash
|
||||||
|
main.cpp
|
||||||
|
SystemInfo.cpp
|
||||||
|
SystemInfo.h
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_add_qml_module(bottomdash
|
||||||
|
URI BottomDash
|
||||||
|
VERSION 1.0
|
||||||
|
QML_FILES
|
||||||
|
Main.qml
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(bottomdash
|
||||||
|
PRIVATE Qt6::Quick
|
||||||
|
)
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Window
|
||||||
|
|
||||||
|
Window {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
width: 1240
|
||||||
|
height: 1080
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
flags: Qt.FramelessWindowHint
|
||||||
|
color: "#000000"
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// Clock
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
property date currentTime: new Date()
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
onTriggered: root.currentTime = new Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: clock
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
topMargin: 40
|
||||||
|
leftMargin: 48
|
||||||
|
}
|
||||||
|
|
||||||
|
text: Qt.formatTime(root.currentTime, "h:mm AP")
|
||||||
|
|
||||||
|
color: "#ffffff"
|
||||||
|
|
||||||
|
font {
|
||||||
|
pixelSize: 64
|
||||||
|
weight: Font.Medium
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// Battery
|
||||||
|
//
|
||||||
|
// Fake percentage for the moment. We'll connect this to
|
||||||
|
// /sys/class/power_supply from C++ next.
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
property int batteryPercent: systemInfo.batteryPercent
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: battery
|
||||||
|
|
||||||
|
width: batteryIcon.width + 18 + batteryText.width
|
||||||
|
height: 72
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
right: parent.right
|
||||||
|
topMargin: 40
|
||||||
|
rightMargin: 48
|
||||||
|
}
|
||||||
|
|
||||||
|
// Battery body
|
||||||
|
Rectangle {
|
||||||
|
id: batteryIcon
|
||||||
|
|
||||||
|
width: 72
|
||||||
|
height: 38
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
border {
|
||||||
|
width: 4
|
||||||
|
color: "#ffffff"
|
||||||
|
}
|
||||||
|
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
// Battery fill
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
|
||||||
|
leftMargin: 7
|
||||||
|
topMargin: 7
|
||||||
|
bottomMargin: 7
|
||||||
|
}
|
||||||
|
|
||||||
|
width: Math.max(
|
||||||
|
0,
|
||||||
|
(parent.width - 14) *
|
||||||
|
root.batteryPercent / 100
|
||||||
|
)
|
||||||
|
|
||||||
|
color: {
|
||||||
|
if (root.batteryPercent <= 15)
|
||||||
|
return "#ff453a"
|
||||||
|
|
||||||
|
if (root.batteryPercent <= 35)
|
||||||
|
return "#ffd60a"
|
||||||
|
|
||||||
|
return "#32d74b"
|
||||||
|
}
|
||||||
|
|
||||||
|
radius: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Battery terminal
|
||||||
|
Rectangle {
|
||||||
|
width: 7
|
||||||
|
height: 18
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
left: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
color: "#ffffff"
|
||||||
|
|
||||||
|
topRightRadius: 3
|
||||||
|
bottomRightRadius: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: batteryText
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
left: batteryIcon.right
|
||||||
|
leftMargin: 18
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
text: root.batteryPercent + "%"
|
||||||
|
|
||||||
|
color: "#ffffff"
|
||||||
|
|
||||||
|
font {
|
||||||
|
pixelSize: 64
|
||||||
|
weight: Font.Medium
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#include "SystemInfo.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
SystemInfo::SystemInfo(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
m_capacityPath = findBatteryCapacityPath();
|
||||||
|
|
||||||
|
updateBattery();
|
||||||
|
|
||||||
|
connect(&m_batteryTimer,
|
||||||
|
&QTimer::timeout,
|
||||||
|
this,
|
||||||
|
&SystemInfo::updateBattery);
|
||||||
|
|
||||||
|
// Battery percentage doesn't need millisecond precision.
|
||||||
|
m_batteryTimer.start(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemInfo::batteryPercent() const
|
||||||
|
{
|
||||||
|
return m_batteryPercent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SystemInfo::findBatteryCapacityPath() const
|
||||||
|
{
|
||||||
|
QDir powerSupply("/sys/class/power_supply");
|
||||||
|
|
||||||
|
const QStringList devices =
|
||||||
|
powerSupply.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
|
for (const QString &device : devices) {
|
||||||
|
const QString base =
|
||||||
|
powerSupply.absoluteFilePath(device);
|
||||||
|
|
||||||
|
QFile typeFile(base + "/type");
|
||||||
|
|
||||||
|
if (!typeFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QString type =
|
||||||
|
QString::fromUtf8(typeFile.readAll()).trimmed();
|
||||||
|
|
||||||
|
if (type != "Battery")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QString capacityPath = base + "/capacity";
|
||||||
|
|
||||||
|
if (QFile::exists(capacityPath))
|
||||||
|
return capacityPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInfo::updateBattery()
|
||||||
|
{
|
||||||
|
if (m_capacityPath.isEmpty())
|
||||||
|
m_capacityPath = findBatteryCapacityPath();
|
||||||
|
|
||||||
|
if (m_capacityPath.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QFile capacityFile(m_capacityPath);
|
||||||
|
|
||||||
|
if (!capacityFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
int percent =
|
||||||
|
QString::fromUtf8(capacityFile.readAll())
|
||||||
|
.trimmed()
|
||||||
|
.toInt(&ok);
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
percent = qBound(0, percent, 100);
|
||||||
|
|
||||||
|
if (percent == m_batteryPercent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_batteryPercent = percent;
|
||||||
|
emit batteryPercentChanged();
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class SystemInfo : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(int batteryPercent
|
||||||
|
READ batteryPercent
|
||||||
|
NOTIFY batteryPercentChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SystemInfo(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int batteryPercent() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void batteryPercentChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateBattery();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString findBatteryCapacityPath() const;
|
||||||
|
|
||||||
|
int m_batteryPercent = -1;
|
||||||
|
QString m_capacityPath;
|
||||||
|
QTimer m_batteryTimer;
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QQmlContext>
|
||||||
|
|
||||||
|
#include "SystemInfo.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
|
SystemInfo systemInfo;
|
||||||
|
|
||||||
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
|
engine.rootContext()->setContextProperty(
|
||||||
|
"systemInfo",
|
||||||
|
&systemInfo
|
||||||
|
);
|
||||||
|
|
||||||
|
engine.loadFromModule("BottomDash", "Main");
|
||||||
|
|
||||||
|
if (engine.rootObjects().isEmpty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user