Skip to content

Commit 76b190f

Browse files
committed
refactor: create FrameBuilder
1 parent 931bca9 commit 76b190f

File tree

4 files changed

+140
-128
lines changed

4 files changed

+140
-128
lines changed

src/App.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "domain/Trip.h"
55
#include "hardware/Gnss.h"
66
#include "hardware/OLED.h"
7+
#include "ui/Frame.h"
8+
#include "ui/FrameBuilder.h"
79
#include "ui/Input.h"
810
#include "ui/Mode.h"
911
#include "ui/Renderer.h"
@@ -16,6 +18,7 @@ class App {
1618
Mode mode;
1719
Trip trip;
1820
Clock clock;
21+
FrameBuilder frameBuilder;
1922
Renderer<OLED> renderer;
2023

2124
public:
@@ -35,7 +38,10 @@ class App {
3538
const auto &navData = gnss.getNavData();
3639
trip.update(navData, millis());
3740
clock.update(navData);
38-
renderer.render(display, trip, clock, mode.get(), (SpFixMode)navData.posFixMode, navData.numSatellites);
41+
42+
Frame frame;
43+
frameBuilder.build(frame, trip, clock, mode.get(), (SpFixMode)navData.posFixMode, navData.numSatellites);
44+
renderer.render(display, frame);
3945
}
4046

4147
private:

src/ui/Frame.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
#include <cstring>
4+
5+
struct Frame {
6+
char title[16];
7+
char value[32];
8+
char unit[16];
9+
char fixStatus[8];
10+
char satelliteCount[8];
11+
12+
bool operator==(const Frame &other) const {
13+
return strcmp(title, other.title) == 0 && strcmp(value, other.value) == 0 && strcmp(unit, other.unit) == 0 &&
14+
strcmp(fixStatus, other.fixStatus) == 0 && strcmp(satelliteCount, other.satelliteCount) == 0;
15+
}
16+
};

src/ui/FrameBuilder.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#pragma once
2+
3+
#include <GNSS.h>
4+
#include <cstring>
5+
6+
#include "../domain/Clock.h"
7+
#include "../domain/Trip.h"
8+
#include "Formatter.h"
9+
#include "Frame.h"
10+
#include "Mode.h"
11+
12+
class FrameBuilder {
13+
public:
14+
void build(Frame &frame, const Trip &trip, const Clock &clock, Mode::ID modeId, SpFixMode fixMode, int numSatellites) {
15+
getModeData(frame, trip, clock, modeId);
16+
17+
switch (fixMode) {
18+
case FixInvalid:
19+
strcpy(frame.fixStatus, "WAIT");
20+
break;
21+
case Fix2D:
22+
strcpy(frame.fixStatus, "2D");
23+
break;
24+
case Fix3D:
25+
strcpy(frame.fixStatus, "3D");
26+
break;
27+
default:
28+
frame.fixStatus[0] = '\0';
29+
break;
30+
}
31+
32+
snprintf(frame.satelliteCount, sizeof(frame.satelliteCount), "St:%d", numSatellites);
33+
}
34+
35+
private:
36+
void getModeData(Frame &frame, const Trip &trip, const Clock &clock, Mode::ID modeId) {
37+
switch (modeId) {
38+
case Mode::ID::SPEED:
39+
strcpy(frame.title, "SPEED");
40+
Formatter::formatSpeed(trip.speedometer.get(), frame.value, sizeof(frame.value));
41+
strcpy(frame.unit, "km/h");
42+
break;
43+
case Mode::ID::MAX_SPEED:
44+
strcpy(frame.title, "MAX SPEED");
45+
Formatter::formatSpeed(trip.speedometer.getMax(), frame.value, sizeof(frame.value));
46+
strcpy(frame.unit, "km/h");
47+
break;
48+
case Mode::ID::AVG_SPEED:
49+
strcpy(frame.title, "AVG SPEED");
50+
Formatter::formatSpeed(trip.getAvgSpeedKmh(), frame.value, sizeof(frame.value));
51+
strcpy(frame.unit, "km/h");
52+
break;
53+
case Mode::ID::DISTANCE:
54+
strcpy(frame.title, "DISTANCE");
55+
Formatter::formatDistance(trip.odometer.getDistance(), frame.value, sizeof(frame.value));
56+
strcpy(frame.unit, "km");
57+
break;
58+
case Mode::ID::TIME: {
59+
strcpy(frame.title, "TIME");
60+
Clock::Time t = clock.getTime();
61+
Formatter::formatTime(t.hour, t.minute, frame.value, sizeof(frame.value));
62+
frame.unit[0] = '\0';
63+
break;
64+
}
65+
case Mode::ID::MOVING_TIME:
66+
strcpy(frame.title, "TRIP TIME");
67+
Formatter::formatDuration(trip.stopwatch.getMovingTimeMs(), frame.value, sizeof(frame.value));
68+
frame.unit[0] = '\0';
69+
break;
70+
case Mode::ID::ELAPSED_TIME:
71+
strcpy(frame.title, "ELAPSED TIME");
72+
Formatter::formatDuration(trip.stopwatch.getElapsedTimeMs(), frame.value, sizeof(frame.value));
73+
frame.unit[0] = '\0';
74+
break;
75+
}
76+
}
77+
};

src/ui/Renderer.h

Lines changed: 40 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,13 @@
11
#pragma once
22

33
#include <Arduino.h>
4+
#include <GNSS.h>
45
#include <cstring>
56

6-
#include "../domain/Clock.h"
7-
#include "../domain/Trip.h"
8-
#include "Formatter.h"
9-
#include "Mode.h"
10-
#include <GNSS.h>
7+
#include "Frame.h"
118

12-
template <typename ContextT> class Renderer {
9+
template <typename ScreenT> class Renderer {
1310
private:
14-
struct Metadata {
15-
const char *title;
16-
const char *unit;
17-
};
18-
19-
struct Frame {
20-
Mode::ID modeId;
21-
SpFixMode fixMode;
22-
int numSatellites;
23-
char value[32];
24-
25-
bool operator==(const Frame &other) const {
26-
return modeId == other.modeId && fixMode == other.fixMode && numSatellites == other.numSatellites && strcmp(value, other.value) == 0;
27-
}
28-
};
29-
3011
Frame lastFrame;
3112
bool firstRender = true;
3213

@@ -35,141 +16,73 @@ template <typename ContextT> class Renderer {
3516
static constexpr int16_t FOOTER_HEIGHT = 12;
3617

3718
public:
38-
void render(ContextT &ctx, const Trip &trip, const Clock &clock, Mode::ID modeId, SpFixMode fixMode, int numSatellites) {
39-
Frame currentFrame;
40-
currentFrame.modeId = modeId;
41-
currentFrame.fixMode = fixMode;
42-
currentFrame.numSatellites = numSatellites;
43-
getDisplayValue(trip, clock, modeId, currentFrame.value, sizeof(currentFrame.value));
44-
45-
if (!firstRender && currentFrame == lastFrame) return;
19+
void render(ScreenT &screen, const Frame &frame) {
20+
if (!firstRender && frame == lastFrame) return;
4621

4722
// Update Cache
4823
firstRender = false;
49-
lastFrame = currentFrame;
50-
51-
ctx.clear();
52-
drawHeader(ctx, currentFrame.fixMode, currentFrame.numSatellites);
53-
Metadata meta = getMetadata(currentFrame.modeId);
54-
drawMainArea(ctx, meta.title, currentFrame.value, meta.unit);
55-
drawFooter(ctx);
56-
ctx.display();
57-
}
58-
59-
private:
60-
void getDisplayValue(const Trip &trip, const Clock &clock, Mode::ID modeId, char *buf, size_t size) {
61-
switch (modeId) {
62-
case Mode::ID::SPEED:
63-
Formatter::formatSpeed(trip.speedometer.get(), buf, size);
64-
return;
65-
case Mode::ID::MAX_SPEED:
66-
Formatter::formatSpeed(trip.speedometer.getMax(), buf, size);
67-
return;
68-
case Mode::ID::AVG_SPEED:
69-
Formatter::formatSpeed(trip.getAvgSpeedKmh(), buf, size);
70-
return;
71-
case Mode::ID::DISTANCE:
72-
Formatter::formatDistance(trip.odometer.getDistance(), buf, size);
73-
return;
74-
case Mode::ID::TIME: {
75-
Clock::Time t = clock.getTime();
76-
Formatter::formatTime(t.hour, t.minute, buf, size);
77-
return;
78-
}
79-
case Mode::ID::MOVING_TIME:
80-
Formatter::formatDuration(trip.stopwatch.getMovingTimeMs(), buf, size);
81-
return;
82-
case Mode::ID::ELAPSED_TIME:
83-
Formatter::formatDuration(trip.stopwatch.getElapsedTimeMs(), buf, size);
84-
return;
85-
}
86-
}
24+
lastFrame = frame;
8725

88-
Metadata getMetadata(Mode::ID modeId) {
89-
switch (modeId) {
90-
case Mode::ID::SPEED:
91-
return {"SPEED", "km/h"};
92-
case Mode::ID::MAX_SPEED:
93-
return {"MAX SPEED", "km/h"};
94-
case Mode::ID::AVG_SPEED:
95-
return {"AVG SPEED", "km/h"};
96-
case Mode::ID::TIME:
97-
return {"TIME", ""};
98-
case Mode::ID::MOVING_TIME:
99-
return {"TRIP TIME", ""};
100-
case Mode::ID::ELAPSED_TIME:
101-
return {"ELAPSED TIME", ""};
102-
case Mode::ID::DISTANCE:
103-
return {"DISTANCE", "km"};
104-
default:
105-
return {"", ""};
106-
}
26+
screen.clear();
27+
drawHeader(screen, frame.fixStatus, frame.satelliteCount);
28+
drawMainArea(screen, frame.title, frame.value, frame.unit);
29+
drawFooter(screen);
30+
screen.display();
10731
}
10832

109-
void drawHeader(ContextT &ctx, SpFixMode fixMode, int numSatellites) {
110-
ctx.setTextSize(1);
111-
ctx.setTextColor(1); // WHITE
112-
ctx.setCursor(0, 0);
113-
switch (fixMode) {
114-
case FixInvalid:
115-
ctx.print("WAIT");
116-
break;
117-
case Fix2D:
118-
ctx.print("2D");
119-
break;
120-
case Fix3D:
121-
ctx.print("3D");
122-
break;
123-
}
33+
private:
34+
void drawHeader(ScreenT &screen, const char *fixStatus, const char *numSatellites) {
35+
screen.setTextSize(1);
36+
screen.setTextColor(1); // WHITE
37+
screen.setCursor(0, 0);
38+
screen.print(fixStatus);
12439

12540
// Right-aligned satellite count
126-
char satBuf[8];
127-
snprintf(satBuf, sizeof(satBuf), "St:%d", numSatellites);
12841
int16_t x1, y1;
12942
uint16_t w, h;
130-
ctx.getTextBounds(satBuf, 0, 0, &x1, &y1, &w, &h);
131-
ctx.setCursor(ctx.getWidth() - w, 0);
132-
ctx.print(satBuf);
43+
screen.getTextBounds(numSatellites, 0, 0, &x1, &y1, &w, &h);
44+
screen.setCursor(screen.getWidth() - w, 0);
45+
screen.print(numSatellites);
13346

13447
int16_t lineY = HEADER_HEIGHT - 2;
135-
ctx.drawLine(0, lineY, ctx.getWidth(), lineY, 1); // WHITE
48+
screen.drawLine(0, lineY, screen.getWidth(), lineY, 1); // WHITE
13649
}
13750

138-
void drawMainArea(ContextT &ctx, const char *title, const char *value, const char *unit) {
51+
void drawMainArea(ScreenT &screen, const char *title, const char *value, const char *unit) {
13952
int16_t contentTop = HEADER_HEIGHT;
140-
int16_t contentY = ctx.getHeight() - FOOTER_HEIGHT;
53+
int16_t contentY = screen.getHeight() - FOOTER_HEIGHT;
14154

14255
// Title (Top Left of Main Area)
143-
ctx.setTextSize(1);
144-
ctx.setCursor(0, contentTop + 2);
145-
ctx.print(title);
56+
screen.setTextSize(1);
57+
screen.setCursor(0, contentTop + 2);
58+
screen.print(title);
14659

14760
// Value (Large, Centered in remaining space)
148-
ctx.setTextSize(2);
61+
screen.setTextSize(2);
14962
int16_t x1, y1;
15063
uint16_t w, h;
151-
ctx.getTextBounds(value, 0, 0, &x1, &y1, &w, &h);
64+
screen.getTextBounds(value, 0, 0, &x1, &y1, &w, &h);
15265
int16_t valueY = (contentY + contentTop - h) / 2;
153-
ctx.setCursor((ctx.getWidth() - w) / 2, valueY);
154-
ctx.print(value);
66+
screen.setCursor((screen.getWidth() - w) / 2, valueY);
67+
screen.print(value);
15568

15669
// Unit (Bottom Right of Main Area)
15770
if (strlen(unit) != 0) {
158-
ctx.setTextSize(1);
159-
ctx.getTextBounds(unit, 0, 0, &x1, &y1, &w, &h);
160-
ctx.setCursor(ctx.getWidth() - w, contentY - h - 2);
161-
ctx.print(unit);
71+
screen.setTextSize(1);
72+
screen.getTextBounds(unit, 0, 0, &x1, &y1, &w, &h);
73+
screen.setCursor(screen.getWidth() - w, contentY - h - 2);
74+
screen.print(unit);
16275
}
16376
}
16477

165-
void drawFooter(ContextT &ctx) {
166-
int16_t lineY = ctx.getHeight() - FOOTER_HEIGHT;
167-
ctx.drawLine(0, lineY, ctx.getWidth(), lineY, 1); // WHITE
78+
void drawFooter(ScreenT &screen) {
79+
int16_t lineY = screen.getHeight() - FOOTER_HEIGHT;
80+
screen.drawLine(0, lineY, screen.getWidth(), lineY, 1); // WHITE
16881

169-
ctx.setTextSize(1);
82+
screen.setTextSize(1);
17083
int16_t textH = 8; // Approx height for size 1
17184
int16_t textY = lineY + (FOOTER_HEIGHT - textH) / 2 + 1;
172-
ctx.setCursor(0, textY);
173-
ctx.print("Ready"); // Placeholder for status
85+
screen.setCursor(0, textY);
86+
screen.print("Ready"); // Placeholder for status
17487
}
17588
};

0 commit comments

Comments
 (0)