diff --git a/source/app.cpp b/source/app.cpp index 2b87ce0..ebe4eb6 100644 --- a/source/app.cpp +++ b/source/app.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace caps_log { @@ -26,7 +27,7 @@ void ViewDataUpdater::handleFocusedTagChange() { } } else if (newTag == kSelectNoneMenuEntryText) { m_view->setHighlightedDates( - &m_data.tagsPerSection.at(m_view->getSelectedSection()).at(AnnualLogData::kAnyTag)); + &m_data.tagsPerSection.at(m_view->getSelectedSection()).at(AnnualLogData::kAnyOrNoTag)); } else { const auto *const highlighMap = &m_data.tagsPerSection.at(m_view->getSelectedSection()).at(newTag); @@ -43,7 +44,7 @@ void ViewDataUpdater::handleFocusedSectionChange() { } else { m_view->tagMenuItems() = m_tagMenuItemsPerSection.at(newSection); m_view->setHighlightedDates( - &m_data.tagsPerSection.at(newSection).at(AnnualLogData::kAnyTag)); + &m_data.tagsPerSection.at(newSection).at(AnnualLogData::kAnyOrNoTag)); } } @@ -52,18 +53,10 @@ void ViewDataUpdater::updateTagMenuItemsPerSection() { // update menu items const auto allTags = m_data.getAllTags(); - m_tagMenuItemsPerSection[kSelectNoneMenuEntryText] = - makeTagMenuItems(allTags, kSelectNoneMenuEntryText); + m_tagMenuItemsPerSection[kSelectNoneMenuEntryText] = makeTagMenuItems(kSelectNoneMenuEntryText); - // NOTE: gotta itterate over datesWithSection to include sections that do not have tags as they - // are not included in tagsPerSection for (const auto §ion : m_data.getAllSections()) { - if (m_data.tagsPerSection.contains(section)) { - m_tagMenuItemsPerSection[section] = - makeTagMenuItems(m_data.getAllTagsForSection(section), section); - } else { - m_tagMenuItemsPerSection[section] = makeTagMenuItems({}, section); - } + m_tagMenuItemsPerSection[section] = makeTagMenuItems(section); } } @@ -72,11 +65,11 @@ void ViewDataUpdater::updateViewAfterDataChange(const std::string &previewString { const auto oldSections = m_view->sectionMenuItems().getKeys(); if (oldSections.empty()) { // initial start - m_view->sectionMenuItems() = makeSectionMenuItems(m_data.getAllSections()); + m_view->sectionMenuItems() = makeSectionMenuItems(); m_view->setSelectedSection(kSelectNoneMenuEntryText); } else { const auto oldSelectedSection = m_view->getSelectedSection(); - m_view->sectionMenuItems() = makeSectionMenuItems(m_data.getAllSections()); + m_view->sectionMenuItems() = makeSectionMenuItems(); // restore selected section if (std::ranges::find(m_view->sectionMenuItems().getKeys(), oldSelectedSection) != @@ -117,7 +110,7 @@ void ViewDataUpdater::updateViewAfterDataChange(const std::string &previewString m_view->setHighlightedDates(nullptr); } else if (m_view->getSelectedTag() == kSelectNoneMenuEntryText) { m_view->setHighlightedDates( - &m_data.tagsPerSection.at(m_view->getSelectedSection()).at(AnnualLogData::kAnyTag)); + &m_data.tagsPerSection.at(m_view->getSelectedSection()).at(AnnualLogData::kAnyOrNoTag)); } else { m_view->setHighlightedDates( &m_data.tagsPerSection.at(AnnualLogData::kAnySection).at(m_view->getSelectedTag())); @@ -127,6 +120,46 @@ void ViewDataUpdater::updateViewAfterDataChange(const std::string &previewString m_view->setPreviewString(previewString); } +MenuItems ViewDataUpdater::makeTagMenuItems(const std::string §ion) { + std::vector menuItems; + std::vector keys; + + // prepend select none + menuItems.push_back(kSelectNoneMenuEntryText); + keys.push_back(kSelectNoneMenuEntryText); + + const auto sect = section == kSelectNoneMenuEntryText ? AnnualLogData::kAnySection : section; + for (const auto &[tag, dates] : m_data.tagsPerSection.at(sect)) { + if (tag == AnnualLogData::kAnyOrNoTag) { + continue; + } + menuItems.push_back(makeMenuItemTitle(tag, dates.size())); + keys.push_back(tag); + } + return {menuItems, keys}; +} + +MenuItems ViewDataUpdater::makeSectionMenuItems() { + std::vector menuItems; + std::vector keys; + menuItems.reserve(m_data.tagsPerSection.size()); + keys.reserve(m_data.tagsPerSection.size()); + + // prepend select none + menuItems.push_back(kSelectNoneMenuEntryText); + keys.push_back(kSelectNoneMenuEntryText); + + for (const auto §ion : m_data.tagsPerSection | std::views::keys) { + if (section == AnnualLogData::kAnySection) { + continue; + } + menuItems.push_back(makeMenuItemTitle( + section, m_data.tagsPerSection.at(section).at(AnnualLogData::kAnyOrNoTag).size())); + keys.push_back(section); + } + return {menuItems, keys}; +} + void App::updateDataAndViewAfterLogChange(const std::chrono::year_month_day &dateOfChangedLog) { m_data.collect(m_repo, dateOfChangedLog, m_config.skipFirstLine); std::string previewString = ""; diff --git a/source/app.hpp b/source/app.hpp index 570d320..5fa8ddc 100644 --- a/source/app.hpp +++ b/source/app.hpp @@ -44,49 +44,8 @@ class ViewDataUpdater final { private: void updateTagMenuItemsPerSection(); - MenuItems makeTagMenuItems(const std::vector &tags, const std::string §ion) { - std::vector menuItems; - std::vector keys; - menuItems.reserve(tags.size()); - keys.reserve(tags.size()); - - // prepend select none - menuItems.push_back(kSelectNoneMenuEntryText); - keys.push_back(kSelectNoneMenuEntryText); - - const auto sect = - section == kSelectNoneMenuEntryText ? AnnualLogData::kAnySection : section; - for (const auto &tag : tags) { - if (tag == AnnualLogData::kAnyTag) { - continue; - } - menuItems.push_back( - makeMenuItemTitle(tag, m_data.tagsPerSection.at(sect).at(tag).size())); - keys.push_back(tag); - } - return {menuItems, keys}; - } - - MenuItems makeSectionMenuItems(const std::vector §ions) { - std::vector menuItems; - std::vector keys; - menuItems.reserve(sections.size()); - keys.reserve(sections.size()); - - // prepend select none - menuItems.push_back(kSelectNoneMenuEntryText); - keys.push_back(kSelectNoneMenuEntryText); - - for (const auto §ion : sections) { - if (section == AnnualLogData::kAnySection) { - continue; - } - menuItems.push_back(makeMenuItemTitle( - section, m_data.tagsPerSection.at(section).at(AnnualLogData::kAnyTag).size())); - keys.push_back(section); - } - return {menuItems, keys}; - } + MenuItems makeTagMenuItems(const std::string §ion); + MenuItems makeSectionMenuItems(); }; struct AppConfig { diff --git a/source/log/annual_log_data.cpp b/source/log/annual_log_data.cpp index e2934e5..a660232 100644 --- a/source/log/annual_log_data.cpp +++ b/source/log/annual_log_data.cpp @@ -21,8 +21,8 @@ void collectEmpty(AnnualLogData &data, const std::shared_ptr const auto monthDayDate = monthDay(date); for (const auto &[section, tags] : input->getTagsPerSection()) { - data.tagsPerSection[section][AnnualLogData::kAnyTag].insert(monthDayDate); - data.tagsPerSection[AnnualLogData::kAnySection][AnnualLogData::kAnyTag].insert( + data.tagsPerSection[section][AnnualLogData::kAnyOrNoTag].insert(monthDayDate); + data.tagsPerSection[AnnualLogData::kAnySection][AnnualLogData::kAnyOrNoTag].insert( monthDayDate); for (const auto &tag : tags) { data.tagsPerSection[section][tag].insert(monthDayDate); @@ -57,18 +57,17 @@ void AnnualLogData::collect(const std::shared_ptr &repo, const auto monthDayDate = monthDay(date); std::erase_if(tagsPerSection, [monthDayDate](auto &item) { auto &[section, tags] = item; - const auto numOfErased = std::erase_if(tags, [monthDayDate, section](auto &tagAndDates) { + // remove all tags that after removal of this date would be empty (except for ) + std::erase_if(tags, [monthDayDate, section](auto &tagAndDates) { auto &[tag, dates] = tagAndDates; dates.erase(monthDayDate); - if (tag == kAnyTag) { - return false; - } - return dates.size() == 0; + return tag != kAnyOrNoTag && dates.size() == 0; }); if (section == kAnySection) { return false; } - return tags.size() <= 1; // 1 because of the kAnyTag + assert(tags.contains(kAnyOrNoTag)); // should always be present + return section != kAnyOrNoTag && tags.size() == 1 && tags.at(kAnyOrNoTag).empty(); }); // collect as if it was empty diff --git a/source/log/annual_log_data.hpp b/source/log/annual_log_data.hpp index adebeb3..fdbe33f 100644 --- a/source/log/annual_log_data.hpp +++ b/source/log/annual_log_data.hpp @@ -16,7 +16,7 @@ namespace caps_log::log { class AnnualLogData { public: static constexpr auto kAnySection = ""; - static constexpr auto kAnyTag = ""; + static constexpr auto kAnyOrNoTag = ""; utils::date::Dates datesWithLogs; std::map> tagsPerSection; @@ -35,7 +35,7 @@ class AnnualLogData { std::set tags; for (const auto &[_, tagsMap] : tagsPerSection) { for (const auto &[tag, _] : tagsMap) { - if (tag == kAnyTag) { + if (tag == kAnyOrNoTag) { continue; } tags.insert(tag); @@ -52,11 +52,11 @@ class AnnualLogData { tags.push_back(tag); } // remove from the list - tags.erase(std::remove(tags.begin(), tags.end(), kAnyTag), tags.end()); + tags.erase(std::remove(tags.begin(), tags.end(), kAnyOrNoTag), tags.end()); return tags; } - AnnualLogData() { tagsPerSection[kAnySection][kAnyTag] = {}; } + AnnualLogData() { tagsPerSection[kAnySection][kAnyOrNoTag] = {}; } /** * Constructs YearOverviewData from logs in a given year. diff --git a/test/annual_log_data_test.cpp b/test/annual_log_data_test.cpp index 8537e90..3c197f9 100644 --- a/test/annual_log_data_test.cpp +++ b/test/annual_log_data_test.cpp @@ -11,7 +11,7 @@ namespace caps_log::log::test { namespace { using utils::date::monthDay; const auto &kAnySection = AnnualLogData::kAnySection; -const auto &kAnyTag = AnnualLogData::kAnyTag; +const auto &kAnyTag = AnnualLogData::kAnyOrNoTag; const auto dummyDate1 = std::chrono::year_month_day{std::chrono::year{2020}, std::chrono::month{2}, std::chrono::day{3}}; const auto dummyDate2 = std::chrono::year_month_day{std::chrono::year{2020}, std::chrono::month{2}, diff --git a/test/controler_test.cpp b/test/controler_test.cpp index 79ae52b..5b87398 100644 --- a/test/controler_test.cpp +++ b/test/controler_test.cpp @@ -332,9 +332,8 @@ TEST_F(ControllerTest, TagsPerSection_RootSectionNotShownWhenTagsInRootSectionNo capsLog.run(); } -TEST_F( - ControllerTest, - DISABLED_TagsPerSection_SelectingATagPerSectionHighlightsOnlyTheDatesWhereTagIsUnderThatSection) { +TEST_F(ControllerTest, + TagsPerSection_SelectingATagPerSectionHighlightsOnlyTheDatesWhereTagIsUnderThatSection) { mockRepo->write(LogFile{day1, "# DummyContent \n# section 1 \n* tag"}); mockRepo->write(LogFile{day2, "# DummyContent \n# section 1 \nno tag"}); mockRepo->write(LogFile{day3, "# DummyContent \n# section 2 \n* tag"}); @@ -365,7 +364,7 @@ TEST_F( capsLog.run(); } -TEST_F(ControllerTest, DISABLED_SectionWithNoTagIsListedInMenuItems) { +TEST_F(ControllerTest, SectionWithNoTagIsListedInMenuItems) { mockRepo->write(LogFile{day2, "# DummyContent \n# section 1 \nno tag"}); auto capsLog = makeCapsLog(); EXPECT_CALL(*mockView, run());