Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: empty screen on startup #74

Merged
merged 1 commit into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions source/view/annual_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ using namespace ftxui;
AnnualView::AnnualView(const std::chrono::year_month_day &today, bool sundayStart,
unsigned recentEventsWindow)
: m_screen{ScreenInteractive::Fullscreen()},
m_calendarButtons{Calendar::make(m_screen, today, makeCalendarOptions(today, sundayStart))},
m_calendarButtons{Calendar::make(ScreenSizeProvider::makeDefault(), today,
makeCalendarOptions(today, sundayStart))},
m_tagsMenu{makeTagsMenu()}, m_sectionsMenu{makeSectionsMenu()},
m_rootComponent{makeFullUIComponent()}, m_recentEventsWindow{recentEventsWindow} {}

void AnnualView::run() { m_screen.Loop(m_rootComponent); }
void AnnualView::run() {
// Caps-log expects the terminal to be at least 80x24
Terminal::SetFallbackSize(Dimensions{/*dimx=*/80, /*dimy=*/24});
m_screen.Loop(m_rootComponent);
}

void AnnualView::stop() { m_screen.ExitLoopClosure()(); }

Expand Down
20 changes: 12 additions & 8 deletions source/view/calendar_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "view/ftxui_ext/extended_containers.hpp"

#include <ftxui/screen/screen.hpp>
#include <ftxui/screen/terminal.hpp>
#include <memory>

namespace caps_log::view {
using namespace ftxui;
Expand All @@ -20,9 +22,9 @@ namespace {
*/
class MonthComponentArranger {
public:
static Element arrange(const Screen &screen, const Components &monthComponents,
static Element arrange(const Dimensions screenDimensions, const Components &monthComponents,
std::chrono::year displayedYear) {
const auto availableMonthColumns = computeNumberOfMonthsPerRow(screen);
const auto availableMonthColumns = computeNumberOfMonthsPerRow(screenDimensions);
const auto renderData = arrangeMonthsInCalendar(monthComponents, availableMonthColumns);
return window(text(std::to_string(static_cast<int>(displayedYear))),
vbox(renderData) | frame) |
Expand All @@ -40,8 +42,8 @@ class MonthComponentArranger {
/**
* @brief Computes the number of months that can be displayed in a row.
*/
static int computeNumberOfMonthsPerRow(const Screen &screen) {
int availableMonthColumns = screen.dimx() / kCharsPerMonthComponet;
static int computeNumberOfMonthsPerRow(const Dimensions &screenDimensions) {
int availableMonthColumns = screenDimensions.dimx / kCharsPerMonthComponet;
// prevent spliting 12 months into 2 rows of unequal elements
if (availableMonthColumns == 5) { // NOLINT
availableMonthColumns = 4;
Expand Down Expand Up @@ -70,9 +72,10 @@ class MonthComponentArranger {

} // namespace

Calendar::Calendar(const Screen &screen, const std::chrono::year_month_day &today,
CalendarOption option)
: m_screen{&screen}, m_option(std::move(option)), m_today(today),
Calendar::Calendar(std::unique_ptr<ScreenSizeProvider> screenSizeProvider,
const std::chrono::year_month_day &today, CalendarOption option)
: m_screenSizeProvider{std::move(screenSizeProvider)}, m_option(std::move(option)),
m_today(today),
// TODO: SetActiveChild does nothing, this is the only
// way to focus a specific date on startup. Investigate.
m_selectedMonthComponentIdx{(static_cast<int>(static_cast<unsigned>(today.month()))) - 1},
Expand Down Expand Up @@ -130,7 +133,8 @@ Component Calendar::createYear(std::chrono::year year) {
const auto container = ftxui_ext::AnyDir(monthComponents, &m_selectedMonthComponentIdx);

return Renderer(container, [this, monthComponents]() {
return MonthComponentArranger::arrange(*m_screen, monthComponents, m_displayedYear);
return MonthComponentArranger::arrange(m_screenSizeProvider->getScreenSize(),
monthComponents, m_displayedYear);
});
}

Expand Down
28 changes: 22 additions & 6 deletions source/view/calendar_component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,24 @@ struct CalendarOption {
bool sundayStart = false;
};

class ScreenSizeProvider {
public:
virtual ~ScreenSizeProvider() = default;
virtual ftxui::Dimensions getScreenSize() const = 0;

static std::unique_ptr<ScreenSizeProvider> makeDefault() {
// Caps-log runs only in full screen mode, so we can use the terminal size as the screen
// size
class DefaultScreenSizeProvider : public ScreenSizeProvider {
public:
ftxui::Dimensions getScreenSize() const override { return ftxui::Terminal::Size(); }
};
return std::make_unique<DefaultScreenSizeProvider>();
}
};

class Calendar : public ftxui::ComponentBase {
const ftxui::Screen *m_screen;
std::unique_ptr<ScreenSizeProvider> m_screenSizeProvider;
CalendarOption m_option;
std::chrono::year_month_day m_today;
ftxui::Component m_root;
Expand All @@ -27,8 +43,8 @@ class Calendar : public ftxui::ComponentBase {
std::chrono::year m_displayedYear;

public:
Calendar(const ftxui::Screen &screen, const std::chrono::year_month_day &today,
CalendarOption option = {});
Calendar(std::unique_ptr<ScreenSizeProvider> ScreenSizeProvider,
const std::chrono::year_month_day &today, CalendarOption option = {});

bool OnEvent(ftxui::Event event) override;
ftxui::Element Render() override;
Expand All @@ -40,9 +56,9 @@ class Calendar : public ftxui::ComponentBase {
* @brief A utility factory method to create a shared pointer to a Calendar instance. This is
* useful as FTXUI works with shared pointers to ComponentBase instances.
*/
static inline auto make(const ftxui::Screen &screen, const std::chrono::year_month_day &today,
CalendarOption option = {}) {
return std::make_shared<Calendar>(screen, today, option);
static inline auto make(std::unique_ptr<ScreenSizeProvider> screenSizeProvider,
const std::chrono::year_month_day &today, CalendarOption option = {}) {
return std::make_shared<Calendar>(std::move(screenSizeProvider), today, option);
}

private:
Expand Down
28 changes: 23 additions & 5 deletions test/calendar_component_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ std::string readFile(const std::string &path) {
buffer << ifs.rdbuf();
return buffer.str();
}

class MockScreenSizeProvider : public caps_log::view::ScreenSizeProvider {
public:
MockScreenSizeProvider(ftxui::Dimensions size) : m_size{size} {}
ftxui::Dimensions getScreenSize() const override { return m_size; }

private:
ftxui::Dimensions m_size;
};

} // namespace

TEST(CalnedarComponentTest, Render) {
Expand All @@ -37,13 +47,16 @@ TEST(CalnedarComponentTest, Render) {
};
// NOLINTEND
for (const auto &data : testData) {
ftxui::Screen screen{data.screen_width, 41}; // NOLINT
caps_log::view::Calendar calendar{screen, {2024y, std::chrono::January, 1d}}; // NOLINT

ftxui::Dimensions dimensions{data.screen_width, 41}; // NOLINT
ftxui::Screen screen{data.screen_width, 41}; // NOLINT
auto sizeProvider = std::make_unique<MockScreenSizeProvider>(dimensions);
caps_log::view::Calendar calendar{std::move(sizeProvider),
{2024y, std::chrono::January, 1d}}; // NOLINT
ftxui::Render(screen, calendar.Render());
const auto screenRender = screen.ToString();
std::string expectedOutput = readFile(filePath(data));
EXPECT_EQ(screenRender, expectedOutput) << "Got: " << screenRender;
EXPECT_EQ(screenRender, expectedOutput) << "Expected" << expectedOutput << "\n\n"
<< "Got: " << screenRender;
}
}

Expand All @@ -52,15 +65,20 @@ TEST(CalnedarComponentTest, EventHandling) {
std::chrono::year_month_day next{2024y, std::chrono::January, 2d}; // NOLINT
std::chrono::year_month_day next_month{2024y, std::chrono::February, 1d}; // NOLINT
ftxui::Screen screen{184, 41}; // NOLINT
caps_log::view::Calendar calendar{screen, start}; // NOLINT
auto sizeProvider = std::make_unique<MockScreenSizeProvider>(ftxui::Dimensions{184, 41});

caps_log::view::Calendar calendar{std::move(sizeProvider), start};

calendar.OnEvent(ftxui::Event::ArrowRight);
EXPECT_EQ(calendar.getFocusedDate(), next)
<< "Got date: " << caps_log::utils::date::formatToString(calendar.getFocusedDate());

calendar.OnEvent(ftxui::Event::ArrowDown);
calendar.OnEvent(ftxui::Event::ArrowDown);
calendar.OnEvent(ftxui::Event::ArrowDown);
calendar.OnEvent(ftxui::Event::ArrowDown);
calendar.OnEvent(ftxui::Event::ArrowDown);

EXPECT_EQ(calendar.getFocusedDate(), next_month)
<< "Got date: " << caps_log::utils::date::formatToString(calendar.getFocusedDate());
}