mirror of
https://github.com/usatiuk/cardboy.git
synced 2025-10-28 15:17:48 +01:00
lockscreen show progressbar only on hold
This commit is contained in:
@@ -17,7 +17,8 @@ namespace {
|
|||||||
|
|
||||||
using cardboy::sdk::AppContext;
|
using cardboy::sdk::AppContext;
|
||||||
|
|
||||||
constexpr std::uint32_t kRefreshIntervalMs = 500;
|
constexpr std::uint32_t kRefreshIntervalMs = 100;
|
||||||
|
constexpr std::uint32_t kUnlockHoldMs = 1500;
|
||||||
|
|
||||||
using Framebuffer = typename AppContext::Framebuffer;
|
using Framebuffer = typename AppContext::Framebuffer;
|
||||||
using Clock = typename AppContext::Clock;
|
using Clock = typename AppContext::Clock;
|
||||||
@@ -40,8 +41,10 @@ public:
|
|||||||
|
|
||||||
void onStart() override {
|
void onStart() override {
|
||||||
cancelRefreshTimer();
|
cancelRefreshTimer();
|
||||||
lastSnapshot = {};
|
lastSnapshot = {};
|
||||||
dirty = true;
|
holdActive = false;
|
||||||
|
holdProgressMs = 0;
|
||||||
|
dirty = true;
|
||||||
const auto snap = captureTime();
|
const auto snap = captureTime();
|
||||||
renderIfNeeded(snap);
|
renderIfNeeded(snap);
|
||||||
lastSnapshot = snap;
|
lastSnapshot = snap;
|
||||||
@@ -53,12 +56,13 @@ public:
|
|||||||
void handleEvent(const cardboy::sdk::AppEvent& event) override {
|
void handleEvent(const cardboy::sdk::AppEvent& event) override {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case cardboy::sdk::AppEventType::Button:
|
case cardboy::sdk::AppEventType::Button:
|
||||||
if (anyNewPress(event.button))
|
handleButtonEvent(event.button);
|
||||||
context.requestAppSwitchByName(kMenuAppName);
|
|
||||||
break;
|
break;
|
||||||
case cardboy::sdk::AppEventType::Timer:
|
case cardboy::sdk::AppEventType::Timer:
|
||||||
if (event.timer.handle == refreshTimer)
|
if (event.timer.handle == refreshTimer) {
|
||||||
|
advanceHoldProgress();
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,6 +75,8 @@ private:
|
|||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
cardboy::sdk::AppTimerHandle refreshTimer = cardboy::sdk::kInvalidAppTimer;
|
cardboy::sdk::AppTimerHandle refreshTimer = cardboy::sdk::kInvalidAppTimer;
|
||||||
TimeSnapshot lastSnapshot{};
|
TimeSnapshot lastSnapshot{};
|
||||||
|
bool holdActive = false;
|
||||||
|
std::uint32_t holdProgressMs = 0;
|
||||||
|
|
||||||
void cancelRefreshTimer() {
|
void cancelRefreshTimer() {
|
||||||
if (refreshTimer != cardboy::sdk::kInvalidAppTimer) {
|
if (refreshTimer != cardboy::sdk::kInvalidAppTimer) {
|
||||||
@@ -79,12 +85,45 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool anyNewPress(const cardboy::sdk::AppButtonEvent& button) {
|
static bool comboPressed(const cardboy::sdk::InputState& state) { return state.a && state.select; }
|
||||||
const auto& current = button.current;
|
|
||||||
const auto& previous = button.previous;
|
void handleButtonEvent(const cardboy::sdk::AppButtonEvent& button) {
|
||||||
return (current.a && !previous.a) || (current.b && !previous.b) || (current.start && !previous.start) ||
|
const bool comboNow = comboPressed(button.current);
|
||||||
(current.select && !previous.select) || (current.up && !previous.up) || (current.down && !previous.down) ||
|
updateHoldState(comboNow);
|
||||||
(current.left && !previous.left) || (current.right && !previous.right);
|
updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateHoldState(bool comboNow) {
|
||||||
|
if (comboNow) {
|
||||||
|
if (!holdActive) {
|
||||||
|
holdActive = true;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (holdActive || holdProgressMs != 0) {
|
||||||
|
holdActive = false;
|
||||||
|
holdProgressMs = 0;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void advanceHoldProgress() {
|
||||||
|
if (holdActive) {
|
||||||
|
const std::uint32_t next =
|
||||||
|
std::min<std::uint32_t>(holdProgressMs + kRefreshIntervalMs, kUnlockHoldMs);
|
||||||
|
if (next != holdProgressMs) {
|
||||||
|
holdProgressMs = next;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
if (holdProgressMs >= kUnlockHoldMs) {
|
||||||
|
holdActive = false;
|
||||||
|
context.requestAppSwitchByName(kMenuAppName);
|
||||||
|
}
|
||||||
|
} else if (holdProgressMs != 0) {
|
||||||
|
holdProgressMs = 0;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDisplay() {
|
void updateDisplay() {
|
||||||
@@ -133,6 +172,29 @@ private:
|
|||||||
font16x8::drawText(fb, x, y, text, scale, true, letterSpacing);
|
font16x8::drawText(fb, x, y, text, scale, true, letterSpacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drawRectOutline(Framebuffer& fb, int x, int y, int w, int h) {
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
return;
|
||||||
|
for (int dx = 0; dx < w; ++dx) {
|
||||||
|
fb.drawPixel(x + dx, y, true);
|
||||||
|
fb.drawPixel(x + dx, y + h - 1, true);
|
||||||
|
}
|
||||||
|
for (int dy = 0; dy < h; ++dy) {
|
||||||
|
fb.drawPixel(x, y + dy, true);
|
||||||
|
fb.drawPixel(x + w - 1, y + dy, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fillRect(Framebuffer& fb, int x, int y, int w, int h) {
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
return;
|
||||||
|
for (int dy = 0; dy < h; ++dy) {
|
||||||
|
for (int dx = 0; dx < w; ++dx) {
|
||||||
|
fb.drawPixel(x + dx, y + dy, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static std::string formatDate(const TimeSnapshot& snap) {
|
static std::string formatDate(const TimeSnapshot& snap) {
|
||||||
static const char* kWeekdays[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
|
static const char* kWeekdays[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
|
||||||
if (!snap.hasWallTime)
|
if (!snap.hasWallTime)
|
||||||
@@ -169,7 +231,24 @@ private:
|
|||||||
|
|
||||||
const std::string dateLine = formatDate(snap);
|
const std::string dateLine = formatDate(snap);
|
||||||
drawCenteredText(framebuffer, timeY + font16x8::kGlyphHeight * scaleTime + 24, dateLine, scaleSmall, 1);
|
drawCenteredText(framebuffer, timeY + font16x8::kGlyphHeight * scaleTime + 24, dateLine, scaleSmall, 1);
|
||||||
drawCenteredText(framebuffer, framebuffer.height() - 40, "PRESS ANY BUTTON", scaleSmall, 1);
|
const char* instruction = holdActive ? "KEEP HOLDING A+SELECT" : "HOLD A+SELECT";
|
||||||
|
drawCenteredText(framebuffer, framebuffer.height() - 52, instruction, scaleSmall, 1);
|
||||||
|
|
||||||
|
if (holdActive || holdProgressMs > 0) {
|
||||||
|
const int barWidth = framebuffer.width() - 64;
|
||||||
|
const int barHeight = 14;
|
||||||
|
const int barX = (framebuffer.width() - barWidth) / 2;
|
||||||
|
const int barY = framebuffer.height() - 32;
|
||||||
|
const int innerWidth = barWidth - 2;
|
||||||
|
const int innerHeight = barHeight - 2;
|
||||||
|
drawRectOutline(framebuffer, barX, barY, barWidth, barHeight);
|
||||||
|
|
||||||
|
const float ratio =
|
||||||
|
std::clamp(holdProgressMs / static_cast<float>(kUnlockHoldMs), 0.0f, 1.0f);
|
||||||
|
const int fillWidth = static_cast<int>(ratio * innerWidth + 0.5f);
|
||||||
|
if (fillWidth > 0)
|
||||||
|
fillRect(framebuffer, barX + 1, barY + 1, fillWidth, innerHeight);
|
||||||
|
}
|
||||||
|
|
||||||
framebuffer.sendFrame();
|
framebuffer.sendFrame();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user