Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Eeems authored Jan 11, 2024
0 parents commit 7ca94c3
Show file tree
Hide file tree
Showing 15 changed files with 655 additions and 0 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
on:
push:
pull_request:
workflow_dispatch:
jobs:
build:
name: Build and package
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Create source tarball
run: tar -czvf src.tar.gz src
- name: Build package
uses: toltec-dev/build-action@v1
- name: Save packages
uses: actions/upload-artifact@v3
with:
name: packages
path: dist/rm*/*.ipk
- name: Save repo
uses: actions/upload-artifact@v3
with:
name: rmall
path: dist/rmall
test:
name: Test package
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/download-artifact@v3
id: download
with:
name: rmall
- uses: Eeems-Org/run-in-remarkable-action@v1
with:
setup: |
set -ex
echo "src/gz local-rmall file:///opt/tmp/src" > /opt/etc/opkg.conf.d/16-local.conf
run: |
set -ex
echo Y | toltecctl generate-opkg-conf
opkg update
opkg install my-app
# Add steps here to test app
opkg remove my-app
path: ${{ steps.download.outputs.download-path }}
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.build/
dist/
*.pro.user
src.tar.gz
build/
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Eeems

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[![rm1](https://img.shields.io/badge/rM1-supported-green)](https://remarkable.com/store/remarkable) [![rm2](https://img.shields.io/badge/rM2-supported-green)](https://remarkable.com/store/remarkable-2) [![Discord](https://img.shields.io/discord/385916768696139794.svg?label=reMarkable&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/ATqQGfu)

reMarkable Template Qt Application
==================================

- [src/vendor/epaper/epframebuffer.h](src/vendor/epaper/epframebuffer.h) - Methods for direct access to the reMarkable screen.
- [src/vendor/epaper/libqsgepaper.a](src/vendor/epaper/libqsgepaper.a) - Static library that contains the epaper Qt platform. This is required for Qt to be able to interact with the screen on the reMarkable.
- [src/vendor/epaper.pri](src/vendor/epaper.pri) - Include file used by [src/src.pro](src/src.pro) to allow the application to access the epaper Qt platform.
- [src/controller.h](src/controller.h) - Basic controller object that provides an interop between QML and C++.
- [src/main.cpp](src/main.cpp) - Main application code.
- [src/main.qml](src/main.qml) - Main user interface.
- [src/myapp.oxide](src/myapp.oxide) - [Oxide application registration](https://oxide.eeems.codes/documentation/03_application_registration_format.html)
- [src/qml.qrc](src/qml.qrc) - Qt resource file to embed [src/main.qml](src/main.qml) in the built application.
- [src/src.pro](src/src.pro) - Project file. This defines the build and install process.

Building
========

This will result in a `dist` folder that you can copy to your device.

```bash
# Source the correct toolchain
source /opt/codex/rm11x/3.1.15/environment-setup-cortexa7hf-neon-remarkable-linux-gnueabi
mkdir .build
cd .build
qmake ..
make
INSTALL_ROOT="$(pwd)/../dist" make install
cd ..
```

Build toltec package
====================

https://remarkable.guide/devel/package.html

```bash
tar -czvf src.tar.gz src
toltecmk
```
3 changes: 3 additions & 0 deletions myapp.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS = src
INSTALLS += $$SUBDIRS
24 changes: 24 additions & 0 deletions package
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pkgnames=(my-app)
pkgdesc="An example application package"
url=https://example.com
pkgver=0.0.1-1
timestamp=2020-10-09T18:15Z
section=util
maintainer="My Name <[email protected]>"
license=MIT

image=qt:v3.1
source=(src.tar.gz)
sha256sums=(SKIP)

build() {
find . -name "*.pro" -type f -print0 \
| xargs -r -0 sed -i 's/linux-oe-g++/linux-arm-remarkable-g++/g'
qmake
make -j$(nproc)
INSTALL_ROOT="dist" make install
}

package() {
cp -ar "${srcdir}/dist/." "${pkgdir}"
}
69 changes: 69 additions & 0 deletions src/controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#pragma once

#include <QObject>
#include <QTimer>
#include <QQuickItem>
#include <epframebuffer.h>
/*!
* \brief This class serves as a simple interop between QML and C++
*/
class Controller : public QObject {
Q_OBJECT

public:
Controller(QObject* parent) : QObject(parent) {}
~Controller(){}

/*!
* \brief Method called by QML after it's loaded to allow C++ to start interacting with the UI
*/
Q_INVOKABLE void startup(){
qDebug() << "Running controller startup";
QTimer::singleShot(10, [this]{
setState("loaded");
});
}
/*!
* \brief Gets the current state in QML
* \return The current state
*/
QString state() {
if(stateControllerUI == nullptr && !getStateControllerUI()){
return "loading";
}
return stateControllerUI->property("state").toString();
}
/*!
* \brief Sets the current QML state
* \param state The state to use
*/
void setState(QString state){
if(stateControllerUI == nullptr && !getStateControllerUI()){
throw "Unable to find state controller";
}
stateControllerUI->setProperty("state", state);
}
/*!
* \brief Change the root QObject for the QML
* \param root The root QObject
*/
void setRoot(QObject* root){ this->root = root; }

private:
/*!
* \brief The root QObject for the QML
*/
QObject* root = nullptr;
/*!
* \brief The QML state controller
*/
QObject* stateControllerUI = nullptr;
/*!
* \brief Find the QML state controller and cache it's value
* \return The QML state controller QObject
*/
QObject* getStateControllerUI(){
stateControllerUI = root->findChild<QObject*>("stateController");
return stateControllerUI;
}
};
78 changes: 78 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtPlugin>
#include <QtQuick>

#include <cstdlib>
#include <signal.h>

#include "controller.h"

// This is required for Qt to display to the reMarkable's display
Q_IMPORT_PLUGIN(QsgEpaperPlugin)

using namespace std;

void sigHandler(int signal){
::signal(signal, SIG_DFL);
qApp->quit();
}

int main(int argc, char *argv[]){
auto qt_version = qVersion();
qDebug() << "Qt Runtime: " << qt_version;
qDebug() << "Qt Build: " << QT_VERSION_STR;
QCoreApplication::addLibraryPath("/opt/usr/lib/plugins");
// Setup correct Qt settings for application to load
// This will overwrite any passed in environment variables
// If you want to support overriding these values, you will need to either
// check that they are not populated here, or move them to a wrapper script
// and remove this code
qputenv("QMLSCENE_DEVICE", "epaper");
qputenv("QT_QUICK_BACKEND","epaper");
qputenv("QT_QPA_PLATFORM", "epaper:enable_fonts");
qputenv("QT_QPA_GENERIC_PLUGINS", "evdevtablet");
QFile file("/sys/devices/soc0/machine");
if(!file.exists() || !file.open(QIODevice::ReadOnly | QIODevice::Text)){
qDebug() << "Couldn't open " << file.fileName();
return EXIT_FAILURE;
}
QTextStream in(&file);
QString modelName = in.readLine();
if(modelName.startsWith("reMarkable 2")){
qDebug() << "RM2 detected...";
qputenv("QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS", "rotate=180:invertx");
qputenv("QT_QPA_EVDEV_TABLET_PARAMETERS", "");
}else{
qDebug() << "RM1 detected...";
qputenv("QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS", "rotate=180");
qputenv("QT_QPA_EVDEV_TABLET_PARAMETERS", "");
}

QGuiApplication app(argc, argv);
app.setApplicationName("myapp");
app.setApplicationDisplayName("My Application");
app.setApplicationVersion(APP_VERSION);
Controller controller(&app);
QQmlApplicationEngine engine;
QQmlContext* context = engine.rootContext();
// Expose screenGeometry and controller to QML
context->setContextProperty("screenGeometry", app.primaryScreen()->geometry());
context->setContextProperty("controller", &controller);
// Load main.qml from the embedded Qt resource file.
// This is defined in qml.qrc
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty()){
qDebug() << "Nothing to display";
return -1;
}
auto root = engine.rootObjects().first();
controller.setRoot(root);

// Setup some signal handlers to make sure to quit the application normally if these signals are recieved
signal(SIGINT, sigHandler);
signal(SIGSEGV, sigHandler);
signal(SIGTERM, sigHandler);

return app.exec();
}
90 changes: 90 additions & 0 deletions src/main.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import QtQuick 2.10
import QtQuick.Window 2.3
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.0

ApplicationWindow {
id: window
objectName: "window"
visible: stateController.state !== "loading"
width: screenGeometry.width
height: screenGeometry.height
title: Qt.application.displayName
Component.onCompleted: {
controller.startup();
}
header: Rectangle {
color: "black"
height: menu.height
RowLayout {
id: menu
anchors.left: parent.left
anchors.right: parent.right
Label {
text: "⬅️"
color: "white"
topPadding: 5
bottomPadding: 5
leftPadding: 10
rightPadding: 10
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Back button pressed");
if(stateController.state === "loaded"){
console.log("Quitting");
Qt.quit();
return;
}
console.log("Going back to main view");
stateController.state = "loaded";
}
}
}
Item { Layout.fillWidth: true }
Label {
color: "white"
text: window.title
}
Item { Layout.fillWidth: true }
}
}
contentData: [
Rectangle {
anchors.fill: parent
color: "white"
Text {
anchors.centerIn: parent
text: "Hello World!"
}
}
]
StateGroup {
id: stateController
objectName: "stateController"
state: "loading"
states: [
State { name: "loaded" },
State { name: "loading" }
]
transitions: [
Transition {
from: "*"; to: "loaded"
SequentialAnimation {
ScriptAction { script: {
console.log("Display loaded");
} }
}
},
Transition {
from: "*"; to: "loading"
SequentialAnimation {
ScriptAction { script: {
console.log("Loading display");
controller.startup();
} }
}
}
]
}
}
8 changes: 8 additions & 0 deletions src/myapp.oxide
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"displayName": "MyApp",
"description": "Hello World",
"bin": "/opt/bin/myapp",
"icon": "oxide:myapp-48",
"splash": "oxide:splash:myapp-48",
"type": "foreground"
}
5 changes: 5 additions & 0 deletions src/qml.qrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
</qresource>
</RCC>
Loading

0 comments on commit 7ca94c3

Please sign in to comment.