M changelog.md => changelog.md +1 -0
@@ 4,6 4,7 @@
### Added
* `[notes]` Notes application implemented.
+* `[notes]` Notes search engine implemented.
### Changed
M image/assets/lang/English.json => image/assets/lang/English.json +1 -0
@@ 130,6 130,7 @@
"app_notes_delete_note": "Delete",
"app_notes_note_delete_confirmation": "Do you really want to delete this note?",
"app_notes_no_notes": "There are no notes yet.\nPress Left arrow to add new.",
+ "app_notes_search_no_results": "No notes found.",
"app_calllog_title_main": "Calls",
"app_calllog_new_note": "New Note",
M module-apps/application-notes/ApplicationNotes.cpp => module-apps/application-notes/ApplicationNotes.cpp +20 -7
@@ 7,6 7,8 @@
#include "windows/NoteMainWindow.hpp"
#include "windows/NotePreviewWindow.hpp"
#include "windows/NoteEditWindow.hpp"
+#include "windows/SearchEngineWindow.hpp"
+#include "windows/SearchResultsWindow.hpp"
#include <service-db/DBMessage.hpp>
#include <service-db/QueryMessage.hpp>
@@ 80,22 82,33 @@ namespace app
void ApplicationNotes::createUserInterface()
{
- windowsFactory.attach(gui::name::window::main_window, [this](Application *app, const std::string &name) {
- auto notesRepository = std::make_unique<notes::NotesDBRepository>(this);
- auto notesProvider = std::make_shared<notes::NotesListModel>(this, std::move(notesRepository));
+ windowsFactory.attach(gui::name::window::main_window, [](Application *app, const std::string &name) {
+ auto notesRepository = std::make_unique<notes::NotesDBRepository>(app);
+ auto notesProvider = std::make_shared<notes::NotesListModel>(app, std::move(notesRepository));
auto presenter = std::make_unique<notes::NotesMainWindowPresenter>(notesProvider);
return std::make_unique<notes::NoteMainWindow>(app, std::move(presenter));
});
- windowsFactory.attach(gui::name::window::note_preview, [this](Application *app, const std::string &name) {
- auto notesRepository = std::make_unique<notes::NotesDBRepository>(this);
+ windowsFactory.attach(gui::name::window::note_preview, [](Application *app, const std::string &name) {
+ auto notesRepository = std::make_unique<notes::NotesDBRepository>(app);
auto presenter = std::make_unique<notes::NotePreviewWindowPresenter>(std::move(notesRepository));
return std::make_unique<notes::NotePreviewWindow>(app, std::move(presenter));
});
- windowsFactory.attach(gui::name::window::note_edit, [this](Application *app, const std::string &name) {
- auto notesRepository = std::make_unique<notes::NotesDBRepository>(this);
+ windowsFactory.attach(gui::name::window::note_edit, [](Application *app, const std::string &name) {
+ auto notesRepository = std::make_unique<notes::NotesDBRepository>(app);
auto presenter = std::make_unique<notes::NoteEditWindowPresenter>(std::move(notesRepository));
return std::make_unique<notes::NoteEditWindow>(app, std::move(presenter));
});
+ windowsFactory.attach(gui::name::window::notes_search, [](Application *app, const std::string &name) {
+ auto notesRepository = std::make_unique<notes::NotesDBRepository>(app);
+ auto presenter = std::make_unique<notes::SearchEngineWindowPresenter>(std::move(notesRepository));
+ return std::make_unique<notes::SearchEngineWindow>(app, std::move(presenter));
+ });
+ windowsFactory.attach(gui::name::window::notes_search_result, [](Application *app, const std::string &name) {
+ return std::make_unique<notes::SearchResultsWindow>(app);
+ });
+ windowsFactory.attach(gui::name::window::note_dialog, [](Application *app, const std::string &name) {
+ return std::make_unique<gui::Dialog>(app, name);
+ });
windowsFactory.attach(gui::name::window::note_confirm_dialog, [](Application *app, const std::string &name) {
return std::make_unique<gui::DialogYesNo>(app, name);
});
M module-apps/application-notes/ApplicationNotes.hpp => module-apps/application-notes/ApplicationNotes.hpp +3 -0
@@ 10,6 10,9 @@ namespace gui::name::window
{
inline constexpr auto note_preview = "NotePreview";
inline constexpr auto note_edit = "NoteEdit";
+ inline constexpr auto notes_search = "NotesSearch";
+ inline constexpr auto notes_search_result = "NotesSearchResult";
+ inline constexpr auto note_dialog = "Dialog";
inline constexpr auto note_confirm_dialog = "ConfirmDialog";
} // namespace gui::name::window
M module-apps/application-notes/CMakeLists.txt => module-apps/application-notes/CMakeLists.txt +10 -0
@@ 13,29 13,39 @@ target_sources( ${PROJECT_NAME}
PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/ApplicationNotes.cpp"
"${CMAKE_CURRENT_LIST_DIR}/model/NotesListModel.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/model/SearchResultsListModel.cpp"
"${CMAKE_CURRENT_LIST_DIR}/model/NotesRepository.cpp"
"${CMAKE_CURRENT_LIST_DIR}/presenter/NotesMainWindowPresenter.cpp"
"${CMAKE_CURRENT_LIST_DIR}/presenter/NotePreviewWindowPresenter.cpp"
"${CMAKE_CURRENT_LIST_DIR}/presenter/NoteEditWindowPresenter.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/presenter/SearchEngineWindowPresenter.cpp"
"${CMAKE_CURRENT_LIST_DIR}/widgets/NotesItem.cpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/NoteMainWindow.cpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/NotePreviewWindow.cpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/NoteEditWindow.cpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/NotesOptions.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/windows/SearchEngineWindow.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/windows/SearchResultsWindow.cpp"
"${CMAKE_CURRENT_LIST_DIR}/data/NoteSwitchData.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/data/NotesFoundData.cpp"
PUBLIC
"${CMAKE_CURRENT_LIST_DIR}/ApplicationNotes.hpp"
"${CMAKE_CURRENT_LIST_DIR}/model/NotesListModel.hpp"
+ "${CMAKE_CURRENT_LIST_DIR}/model/SearchResultsListModel.hpp"
"${CMAKE_CURRENT_LIST_DIR}/model/NotesRepository.hpp"
"${CMAKE_CURRENT_LIST_DIR}/presenter/NotesMainWindowPresenter.hpp"
"${CMAKE_CURRENT_LIST_DIR}/presenter/NotePreviewWindowPresenter.hpp"
"${CMAKE_CURRENT_LIST_DIR}/presenter/NoteEditWindowPresenter.hpp"
+ "${CMAKE_CURRENT_LIST_DIR}/presenter/SearchEngineWindowPresenter.hpp"
"${CMAKE_CURRENT_LIST_DIR}/widgets/NotesItem.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/NoteMainWindow.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/NotePreviewWindow.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/NoteEditWindow.hpp"
+ "${CMAKE_CURRENT_LIST_DIR}/windows/SearchEngineWindow.hpp"
+ "${CMAKE_CURRENT_LIST_DIR}/windows/SearchResultsWindow.hpp"
"${CMAKE_CURRENT_LIST_DIR}/windows/NotesOptions.hpp"
"${CMAKE_CURRENT_LIST_DIR}/data/NoteSwitchData.hpp"
+ "${CMAKE_CURRENT_LIST_DIR}/data/NotesFoundData.hpp"
)
target_include_directories(${PROJECT_NAME}
PRIVATE
A module-apps/application-notes/data/NotesFoundData.cpp => module-apps/application-notes/data/NotesFoundData.cpp +22 -0
@@ 0,0 1,22 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "NotesFoundData.hpp"
+
+namespace app::notes
+{
+ NotesFoundData::NotesFoundData(std::string searchText, std::vector<NotesRecord> notes)
+ : gui::SwitchData(std::string{"NotesFoundData"}), searchText{std::move(searchText)}, recordsFound{
+ std::move(notes)}
+ {}
+
+ const std::string &NotesFoundData::getSearchText() const noexcept
+ {
+ return searchText;
+ }
+
+ const std::vector<NotesRecord> &NotesFoundData::getFoundRecords() const noexcept
+ {
+ return recordsFound;
+ }
+} // namespace app::notes
A module-apps/application-notes/data/NotesFoundData.hpp => module-apps/application-notes/data/NotesFoundData.hpp +25 -0
@@ 0,0 1,25 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <string>
+
+#include <module-db/Interface/NotesRecord.hpp>
+#include <module-gui/gui/SwitchData.hpp>
+
+namespace app::notes
+{
+ class NotesFoundData : public gui::SwitchData
+ {
+ public:
+ NotesFoundData(std::string searchText, std::vector<NotesRecord> notes);
+
+ const std::string &getSearchText() const noexcept;
+ const std::vector<NotesRecord> &getFoundRecords() const noexcept;
+
+ private:
+ std::string searchText;
+ std::vector<NotesRecord> recordsFound;
+ };
+} // namespace app::notes
M module-apps/application-notes/model/NotesRepository.cpp => module-apps/application-notes/model/NotesRepository.cpp +17 -0
@@ 4,6 4,7 @@
#include "NotesRepository.hpp"
#include <module-db/queries/notes/QueryNotesGet.hpp>
+#include <module-db/queries/notes/QueryNotesGetByText.hpp>
#include <module-db/queries/notes/QueryNoteStore.hpp>
#include <module-db/queries/notes/QueryNoteRemove.hpp>
@@ 30,6 31,22 @@ namespace app::notes
DBServiceAPI::GetQuery(application, db::Interface::Name::Notes, std::move(query));
}
+ void NotesDBRepository::getByText(const std::string &text, const OnFilteredCallback &callback)
+ {
+ auto query = std::make_unique<db::query::QueryNotesGetByText>(text);
+ query->setQueryListener(db::QueryCallback::fromFunction([callback](auto response) {
+ auto result = dynamic_cast<db::query::NotesGetByTextResult *>(response);
+ if (result == nullptr) {
+ return false;
+ }
+ if (callback) {
+ callback(result->getRecords());
+ }
+ return true;
+ }));
+ DBServiceAPI::GetQuery(application, db::Interface::Name::Notes, std::move(query));
+ }
+
void NotesDBRepository::save(const NotesRecord ¬e, const OnResultCallback &callback)
{
auto query = std::make_unique<db::query::QueryNoteStore>(note);
M module-apps/application-notes/model/NotesRepository.hpp => module-apps/application-notes/model/NotesRepository.hpp +5 -2
@@ 14,12 14,14 @@ namespace app::notes
class AbstractNotesRepository
{
public:
- using OnGetCallback = std::function<bool(const std::vector<NotesRecord> &, unsigned int)>;
- using OnResultCallback = std::function<void(bool)>;
+ using OnGetCallback = std::function<bool(const std::vector<NotesRecord> &, unsigned int)>;
+ using OnFilteredCallback = std::function<void(const std::vector<NotesRecord> &)>;
+ using OnResultCallback = std::function<void(bool)>;
virtual ~AbstractNotesRepository() noexcept = default;
virtual void get(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback) = 0;
+ virtual void getByText(const std::string &text, const OnFilteredCallback &callback) = 0;
virtual void save(const NotesRecord ¬e, const OnResultCallback &callback) = 0;
virtual void remove(const NotesRecord ¬e, const OnResultCallback &callback) = 0;
};
@@ 30,6 32,7 @@ namespace app::notes
explicit NotesDBRepository(Application *application);
void get(std::uint32_t offset, std::uint32_t limit, const OnGetCallback &callback) override;
+ void getByText(const std::string &text, const OnFilteredCallback &callback) override;
void save(const NotesRecord ¬e, const OnResultCallback &callback) override;
void remove(const NotesRecord ¬e, const OnResultCallback &callback) override;
A module-apps/application-notes/model/SearchResultsListModel.cpp => module-apps/application-notes/model/SearchResultsListModel.cpp +59 -0
@@ 0,0 1,59 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "SearchResultsListModel.hpp"
+
+#include "module-apps/application-notes/style/NotesListStyle.hpp"
+#include "module-apps/application-notes/data/NoteSwitchData.hpp"
+
+#include <module-gui/gui/widgets/ListView.hpp>
+#include <module-apps/application-notes/ApplicationNotes.hpp>
+
+namespace app::notes
+{
+ SearchResultsListModel::SearchResultsListModel(Application *application) : application{application}
+ {}
+
+ void SearchResultsListModel::setResults(const std::vector<NotesRecord> &results)
+ {
+ eraseInternalData();
+ for (const auto ¬e : results) {
+ auto item = createItem(note);
+ internalData.push_back(std::move(item));
+ }
+ }
+
+ gui::NotesItem *SearchResultsListModel::createItem(const NotesRecord &record) const
+ {
+ auto item = new gui::NotesItem(std::make_shared<NotesRecord>(record));
+ item->deleteByList = false;
+ item->activatedCallback = [this, record](gui::Item &) {
+ auto data = std::make_unique<NoteSwitchData>(record);
+ data->ignoreCurrentWindowOnStack = true;
+ application->switchWindow(gui::name::window::note_preview, std::move(data));
+ return true;
+ };
+ return item;
+ }
+
+ void SearchResultsListModel::requestRecords(std::uint32_t offset, std::uint32_t limit)
+ {
+ setupModel(offset, limit);
+ list->onProviderDataUpdate();
+ }
+
+ unsigned int SearchResultsListModel::requestRecordsCount()
+ {
+ return internalData.size();
+ }
+
+ gui::ListItem *SearchResultsListModel::getItem(gui::Order order)
+ {
+ return getRecord(order);
+ }
+
+ unsigned int SearchResultsListModel::getMinimalItemHeight() const
+ {
+ return style::list::item::Height;
+ }
+} // namespace app::notes
A module-apps/application-notes/model/SearchResultsListModel.hpp => module-apps/application-notes/model/SearchResultsListModel.hpp +34 -0
@@ 0,0 1,34 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include <module-db/Interface/NotesRecord.hpp>
+
+#include <module-apps/InternalModel.hpp>
+#include "module-apps/application-notes/widgets/NotesItem.hpp"
+#include <module-gui/gui/widgets/ListItemProvider.hpp>
+
+namespace app::notes
+{
+ class SearchResultsListModel : public InternalModel<gui::NotesItem *>, public gui::ListItemProvider
+ {
+ public:
+ explicit SearchResultsListModel(Application *application);
+
+ void setResults(const std::vector<NotesRecord> &results);
+
+ void requestRecords(std::uint32_t offset, std::uint32_t limit) override;
+ unsigned int requestRecordsCount() override;
+ unsigned int getMinimalItemHeight() const override;
+ gui::ListItem *getItem(gui::Order order) override;
+
+ private:
+ gui::NotesItem *createItem(const NotesRecord &record) const;
+
+ Application *application;
+ };
+} // namespace app::notes
A module-apps/application-notes/presenter/SearchEngineWindowPresenter.cpp => module-apps/application-notes/presenter/SearchEngineWindowPresenter.cpp +21 -0
@@ 0,0 1,21 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "SearchEngineWindowPresenter.hpp"
+
+namespace app::notes
+{
+ SearchEngineWindowPresenter::SearchEngineWindowPresenter(std::unique_ptr<AbstractNotesRepository> &¬esRepository)
+ : notesRepository{std::move(notesRepository)}
+ {}
+
+ void SearchEngineWindowPresenter::searchFor(const std::string &searchText)
+ {
+ if (searchText.empty()) {
+ getView()->notesFound({}, searchText);
+ return;
+ }
+ notesRepository->getByText(
+ searchText, [searchText, this](const auto &records) { getView()->notesFound(records, searchText); });
+ }
+} // namespace app::notes
A module-apps/application-notes/presenter/SearchEngineWindowPresenter.hpp => module-apps/application-notes/presenter/SearchEngineWindowPresenter.hpp +41 -0
@@ 0,0 1,41 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "BasePresenter.hpp"
+
+#include <module-apps/application-notes/model/NotesRepository.hpp>
+
+namespace app::notes
+{
+ class SearchEngineWindowContract
+ {
+ public:
+ class View
+ {
+ public:
+ virtual ~View() noexcept = default;
+
+ virtual void notesFound(const std::vector<NotesRecord> ¬es, const std::string &searchText) = 0;
+ };
+ class Presenter : public BasePresenter<SearchEngineWindowContract::View>
+ {
+ public:
+ virtual ~Presenter() noexcept = default;
+
+ virtual void searchFor(const std::string &searchText) = 0;
+ };
+ };
+
+ class SearchEngineWindowPresenter : public SearchEngineWindowContract::Presenter
+ {
+ public:
+ explicit SearchEngineWindowPresenter(std::unique_ptr<AbstractNotesRepository> &¬esRepository);
+
+ void searchFor(const std::string &searchText) override;
+
+ private:
+ std::unique_ptr<AbstractNotesRepository> notesRepository;
+ };
+} // namespace app::notes
M module-apps/application-notes/windows/NoteMainWindow.cpp => module-apps/application-notes/windows/NoteMainWindow.cpp +3 -0
@@ 167,6 167,9 @@ namespace app::notes
application->switchWindow(gui::name::window::note_edit,
std::make_unique<NoteSwitchData>(NotesRecord{}));
}
+ else if (inputEvent.is(gui::KeyCode::KEY_RIGHT)) {
+ application->switchWindow(gui::name::window::notes_search);
+ }
}
return AppWindow::onInput(inputEvent);
}
A module-apps/application-notes/windows/SearchEngineWindow.cpp => module-apps/application-notes/windows/SearchEngineWindow.cpp +61 -0
@@ 0,0 1,61 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "SearchEngineWindow.hpp"
+
+#include <module-apps/application-notes/ApplicationNotes.hpp>
+#include <module-apps/application-notes/data/NotesFoundData.hpp>
+#include <module-apps/widgets/InputBox.hpp>
+
+#include <module-utils/i18n/i18n.hpp>
+
+namespace app::notes
+{
+ SearchEngineWindow::SearchEngineWindow(Application *application,
+ std::unique_ptr<SearchEngineWindowContract::Presenter> &&windowPresenter)
+ : gui::AppWindow{application, gui::name::window::notes_search}, presenter{std::move(windowPresenter)}
+ {
+ presenter->attach(this);
+ buildInterface();
+ }
+
+ SearchEngineWindow::~SearchEngineWindow() noexcept
+ {
+ destroyInterface();
+ }
+
+ void SearchEngineWindow::buildInterface()
+ {
+ AppWindow::buildInterface();
+ setTitle(utils::localize.get("app_notes_title_main"));
+
+ bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
+ bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(style::strings::common::search));
+ bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
+ bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(style::strings::common::back));
+
+ input = gui::inputBox(this, utils::localize.get("common_search_uc"), "search");
+ setFocusItem(input);
+ }
+
+ void SearchEngineWindow::destroyInterface()
+ {
+ erase();
+ input = nullptr;
+ }
+
+ bool SearchEngineWindow::onInput(const gui::InputEvent &inputEvent)
+ {
+ if (inputEvent.isShortPress() && inputEvent.is(gui::KeyCode::KEY_ENTER)) {
+ presenter->searchFor(input->getText());
+ return true;
+ }
+ return AppWindow::onInput(inputEvent);
+ }
+
+ void SearchEngineWindow::notesFound(const std::vector<NotesRecord> ¬es, const std::string &searchText)
+ {
+ application->switchWindow(gui::name::window::notes_search_result,
+ std::make_unique<NotesFoundData>(searchText, notes));
+ }
+} // namespace app::notes
A module-apps/application-notes/windows/SearchEngineWindow.hpp => module-apps/application-notes/windows/SearchEngineWindow.hpp +33 -0
@@ 0,0 1,33 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include "AppWindow.hpp"
+
+#include <module-apps/Application.hpp>
+#include <module-apps/application-notes/presenter/SearchEngineWindowPresenter.hpp>
+
+#include <module-gui/gui/input/InputEvent.hpp>
+#include <module-gui/gui/widgets/Text.hpp>
+
+namespace app::notes
+{
+ class SearchEngineWindow : public gui::AppWindow, public SearchEngineWindowContract::View
+ {
+ public:
+ SearchEngineWindow(Application *application,
+ std::unique_ptr<SearchEngineWindowContract::Presenter> &&windowPresenter);
+ ~SearchEngineWindow() noexcept override;
+
+ void buildInterface() override;
+ void destroyInterface() override;
+ bool onInput(const gui::InputEvent &inputEvent) override;
+
+ void notesFound(const std::vector<NotesRecord> ¬es, const std::string &searchText) override;
+
+ private:
+ std::unique_ptr<SearchEngineWindowContract::Presenter> presenter;
+ gui::Text *input = nullptr;
+ };
+} // namespace app::notes
A module-apps/application-notes/windows/SearchResultsWindow.cpp => module-apps/application-notes/windows/SearchResultsWindow.cpp +76 -0
@@ 0,0 1,76 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "SearchResultsWindow.hpp"
+
+#include <module-apps/application-notes/ApplicationNotes.hpp>
+#include <module-apps/application-notes/data/NotesFoundData.hpp>
+#include <module-apps/application-notes/style/NotesListStyle.hpp>
+#include <module-apps/windows/DialogMetadata.hpp>
+#include <module-apps/messages/DialogMetadataMessage.hpp>
+
+namespace app::notes
+{
+ SearchResultsWindow::SearchResultsWindow(Application *application)
+ : AppWindow(application, gui::name::window::notes_search_result), listModel{
+ std::make_shared<SearchResultsListModel>(
+ application)}
+ {
+ buildInterface();
+ }
+
+ SearchResultsWindow::~SearchResultsWindow() noexcept
+ {
+ destroyInterface();
+ }
+
+ void SearchResultsWindow::buildInterface()
+ {
+ AppWindow::buildInterface();
+ setTitle(utils::localize.get("app_notes_title_main"));
+
+ bottomBar->setActive(gui::BottomBar::Side::CENTER, true);
+ bottomBar->setText(gui::BottomBar::Side::CENTER, utils::localize.get(::style::strings::common::open));
+ bottomBar->setActive(gui::BottomBar::Side::RIGHT, true);
+ bottomBar->setText(gui::BottomBar::Side::RIGHT, utils::localize.get(::style::strings::common::back));
+
+ list =
+ new gui::ListView(this, style::list::X, style::list::Y, style::list::Width, style::list::Height, listModel);
+ list->setScrollTopMargin(::style::margins::small);
+ setFocusItem(list);
+ }
+
+ void SearchResultsWindow::destroyInterface()
+ {
+ erase();
+ list = nullptr;
+ }
+
+ void SearchResultsWindow::onBeforeShow(gui::ShowMode mode, gui::SwitchData *data)
+ {
+ auto foundNotesData = dynamic_cast<NotesFoundData *>(data);
+ if (foundNotesData == nullptr) {
+ onNothingFound();
+ return;
+ }
+
+ if (const auto &records = foundNotesData->getFoundRecords(); !records.empty()) {
+ listModel->setResults(records);
+ list->rebuildList();
+ setFocusItem(list);
+ }
+ else {
+ onNothingFound(foundNotesData->getSearchText());
+ }
+ }
+
+ void SearchResultsWindow::onNothingFound(const std::string &searchText)
+ {
+ gui::DialogMetadata meta{utils::localize.get("common_results_prefix") + searchText,
+ "search_big",
+ utils::localize.get("app_notes_search_no_results")};
+ auto data = std::make_unique<gui::DialogMetadataMessage>(meta);
+ data->ignoreCurrentWindowOnStack = true;
+ application->switchWindow(gui::name::window::note_dialog, std::move(data));
+ }
+} // namespace app::notes
A module-apps/application-notes/windows/SearchResultsWindow.hpp => module-apps/application-notes/windows/SearchResultsWindow.hpp +34 -0
@@ 0,0 1,34 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <memory>
+
+#include "AppWindow.hpp"
+
+#include <module-apps/Application.hpp>
+#include <module-apps/application-notes/model/SearchResultsListModel.hpp>
+
+#include <module-gui/gui/widgets/ListView.hpp>
+
+namespace app::notes
+{
+ class SearchResultsWindow : public gui::AppWindow
+ {
+ public:
+ explicit SearchResultsWindow(Application *application);
+ ~SearchResultsWindow() noexcept override;
+
+ void buildInterface() override;
+ void destroyInterface() override;
+
+ void onBeforeShow(gui::ShowMode mode, gui::SwitchData *data) override;
+
+ private:
+ void onNothingFound(const std::string &searchText = {});
+
+ std::shared_ptr<SearchResultsListModel> listModel;
+ gui::ListView *list = nullptr;
+ };
+} // namespace app::notes
M module-db/CMakeLists.txt => module-db/CMakeLists.txt +1 -0
@@ 88,6 88,7 @@ set(SOURCES
queries/messages/threads/QueryThreadRemove.cpp
queries/messages/threads/QueryThreadMarkAsRead.cpp
queries/notes/QueryNotesGet.cpp
+ queries/notes/QueryNotesGetByText.cpp
queries/notes/QueryNoteStore.cpp
queries/notes/QueryNoteRemove.cpp
queries/calllog/QueryCalllogSetAllRead.cpp
M module-db/Interface/NotesRecord.cpp => module-db/Interface/NotesRecord.cpp +27 -3
@@ 4,6 4,7 @@
#include "NotesRecord.hpp"
#include "queries/notes/QueryNotesGet.hpp"
+#include "queries/notes/QueryNotesGetByText.hpp"
#include "queries/notes/QueryNoteStore.hpp"
#include "queries/notes/QueryNoteRemove.hpp"
@@ 96,9 97,20 @@ NotesRecord NotesRecordInterface::GetByID(std::uint32_t id)
std::vector<NotesRecord> NotesRecordInterface::getNotes(std::uint32_t offset, std::uint32_t limit) const
{
std::vector<NotesRecord> records;
- const auto notes = notesDB->notes.getLimitOffset(offset, limit);
- for (const auto &w : notes) {
- NotesRecord record{w.ID, w.date, w.snippet};
+ const auto ¬es = notesDB->notes.getLimitOffset(offset, limit);
+ for (const auto ¬e : notes) {
+ NotesRecord record{note.ID, note.date, note.snippet};
+ records.push_back(std::move(record));
+ }
+ return records;
+}
+
+std::vector<NotesRecord> NotesRecordInterface::getNotesByText(const std::string &text) const
+{
+ std::vector<NotesRecord> records;
+ const auto ¬es = notesDB->notes.getByText(text);
+ for (const auto ¬e : notes) {
+ NotesRecord record{note.ID, note.date, note.snippet};
records.push_back(std::move(record));
}
return records;
@@ 109,6 121,9 @@ std::unique_ptr<db::QueryResult> NotesRecordInterface::runQuery(std::shared_ptr<
if (typeid(*query) == typeid(db::query::QueryNotesGet)) {
return getQuery(query);
}
+ if (typeid(*query) == typeid(db::query::QueryNotesGetByText)) {
+ return getByTextQuery(query);
+ }
if (typeid(*query) == typeid(db::query::QueryNoteStore)) {
return storeQuery(query);
}
@@ 127,6 142,15 @@ std::unique_ptr<db::QueryResult> NotesRecordInterface::getQuery(const std::share
return response;
}
+std::unique_ptr<db::QueryResult> NotesRecordInterface::getByTextQuery(const std::shared_ptr<db::Query> &query)
+{
+ const auto localQuery = static_cast<db::query::QueryNotesGetByText *>(query.get());
+ const auto &records = getNotesByText(localQuery->getText());
+ auto response = std::make_unique<db::query::NotesGetByTextResult>(records);
+ response->setRequestQuery(query);
+ return response;
+}
+
std::unique_ptr<db::QueryResult> NotesRecordInterface::storeQuery(const std::shared_ptr<db::Query> &query)
{
const auto localQuery = static_cast<db::query::QueryNoteStore *>(query.get());
M module-db/Interface/NotesRecord.hpp => module-db/Interface/NotesRecord.hpp +2 -0
@@ 47,8 47,10 @@ class NotesRecordInterface : public RecordInterface<NotesRecord, NotesRecordFiel
private:
std::vector<NotesRecord> getNotes(std::uint32_t offset, std::uint32_t limit) const;
+ std::vector<NotesRecord> getNotesByText(const std::string &text) const;
std::unique_ptr<db::QueryResult> getQuery(const std::shared_ptr<db::Query> &query);
+ std::unique_ptr<db::QueryResult> getByTextQuery(const std::shared_ptr<db::Query> &query);
std::unique_ptr<db::QueryResult> storeQuery(const std::shared_ptr<db::Query> &query);
std::unique_ptr<db::QueryResult> removeQuery(const std::shared_ptr<db::Query> &query);
M module-db/Tables/NotesTable.cpp => module-db/Tables/NotesTable.cpp +19 -0
@@ 117,6 117,25 @@ std::vector<NotesTableRow> NotesTable::getLimitOffsetByField(std::uint32_t offse
return ret;
}
+std::vector<NotesTableRow> NotesTable::getByText(const std::string &text)
+{
+ auto retQuery = db->query("SELECT *, INSTR(snippet,'%s') pos FROM notes WHERE pos > 0;", text.c_str());
+ if (retQuery == nullptr || retQuery->getRowCount() == 0) {
+ return {};
+ }
+
+ std::vector<NotesTableRow> records;
+ do {
+ NotesTableRow row{
+ (*retQuery)[0].getUInt32(), // ID
+ (*retQuery)[1].getUInt32(), // date
+ (*retQuery)[2].getString() // snippet
+ };
+ records.push_back(std::move(row));
+ } while (retQuery->nextRow());
+ return records;
+}
+
std::uint32_t NotesTable::count()
{
auto queryRet = db->query("SELECT COUNT(*) FROM notes;");
M module-db/Tables/NotesTable.hpp => module-db/Tables/NotesTable.hpp +1 -0
@@ 41,6 41,7 @@ class NotesTable : public Table<NotesTableRow, NotesTableFields>
std::uint32_t limit,
NotesTableFields field,
const char *str) override;
+ std::vector<NotesTableRow> getByText(const std::string &text);
std::uint32_t count() override;
std::uint32_t countByFieldId(const char *field, std::uint32_t id) override;
A module-db/queries/notes/QueryNotesGetByText.cpp => module-db/queries/notes/QueryNotesGetByText.cpp +33 -0
@@ 0,0 1,33 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "QueryNotesGetByText.hpp"
+
+namespace db::query
+{
+ QueryNotesGetByText::QueryNotesGetByText(std::string text) : Query(Query::Type::Read), text{std::move(text)}
+ {}
+
+ const std::string &QueryNotesGetByText::getText() const noexcept
+ {
+ return text;
+ }
+
+ std::string QueryNotesGetByText::debugInfo() const
+ {
+ return {"QueryNotesGetByText"};
+ }
+
+ NotesGetByTextResult::NotesGetByTextResult(std::vector<NotesRecord> notes) : records{std::move(notes)}
+ {}
+
+ const std::vector<NotesRecord> &NotesGetByTextResult::getRecords() const noexcept
+ {
+ return records;
+ }
+
+ auto NotesGetByTextResult::debugInfo() const -> std::string
+ {
+ return {"NotesGetByTextResult"};
+ }
+} // namespace db::query
A module-db/queries/notes/QueryNotesGetByText.hpp => module-db/queries/notes/QueryNotesGetByText.hpp +36 -0
@@ 0,0 1,36 @@
+// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+
+#include <string>
+
+#include <Common/Query.hpp>
+#include "Interface/NotesRecord.hpp"
+
+namespace db::query
+{
+ class QueryNotesGetByText : public Query
+ {
+ public:
+ explicit QueryNotesGetByText(std::string text);
+
+ [[nodiscard]] const std::string &getText() const noexcept;
+ [[nodiscard]] std::string debugInfo() const override;
+
+ private:
+ std::string text;
+ };
+
+ class NotesGetByTextResult : public QueryResult
+ {
+ public:
+ explicit NotesGetByTextResult(std::vector<NotesRecord> notes);
+
+ [[nodiscard]] const std::vector<NotesRecord> &getRecords() const noexcept;
+ [[nodiscard]] std::string debugInfo() const override;
+
+ private:
+ std::vector<NotesRecord> records;
+ };
+} // namespace db::query
M module-db/tests/NotesRecord_tests.cpp => module-db/tests/NotesRecord_tests.cpp +12 -0
@@ 5,6 5,7 @@
#include <Interface/NotesRecord.hpp>
#include <queries/notes/QueryNotesGet.hpp>
+#include <queries/notes/QueryNotesGetByText.hpp>
#include <queries/notes/QueryNoteRemove.hpp>
#include <queries/notes/QueryNoteStore.hpp>
@@ 40,6 41,17 @@ TEST_CASE("Notes Record tests")
REQUIRE(getResult->getRecords()[0].snippet == testSnippet);
}
+ SECTION("Get notes by text query")
+ {
+ constexpr auto testSearch = "TEST";
+ auto query = std::make_unique<db::query::QueryNotesGetByText>(testSearch);
+ auto response = notesRecordInterface.runQuery(std::move(query));
+ auto getResult = static_cast<db::query::NotesGetByTextResult *>(response.get());
+
+ REQUIRE(getResult->getRecords().size() == 1);
+ REQUIRE(getResult->getRecords()[0].snippet == testSnippet);
+ }
+
SECTION("Add a note")
{
NotesRecord record;
M module-db/tests/NotesTable_tests.cpp => module-db/tests/NotesTable_tests.cpp +8 -0
@@ 33,6 33,14 @@ TEST_CASE("Notes Table tests")
REQUIRE(records[0].snippet == testSnippet);
}
+ SECTION("Get notes by text query")
+ {
+ constexpr auto testSearch = "TEST";
+ const auto &records = table.getByText(testSearch);
+ REQUIRE(records.size() == 1);
+ REQUIRE(records[0].snippet == testSnippet);
+ }
+
SECTION("Add a note")
{
NotesTableRow row;