/* * Copyright (c) 2026-present, the Ladybird developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include namespace WebView { struct WEBVIEW_API HistoryEntry { String url; Optional title; Optional favicon_base64_png; u64 visit_count { 0 }; UnixDateTime last_visited_time; }; struct WEBVIEW_API RecentlyClosedEntry { Vector urls; bool was_window { false }; size_t active_tab_index { 0 }; UnixDateTime closed_time; }; class WEBVIEW_API HistoryStore { AK_MAKE_NONCOPYABLE(HistoryStore); AK_MAKE_NONMOVABLE(HistoryStore); public: static ErrorOr> create(Database::Database&); static NonnullOwnPtr create(); static NonnullOwnPtr create_disabled(); static Optional normalize_url(URL::URL const&); ~HistoryStore(); void record_visit(URL::URL const&, Optional title = {}, UnixDateTime visited_at = UnixDateTime::now()); void update_title(URL::URL const&, String const& title); void update_favicon(URL::URL const&, String const& favicon_base64_png); void record_closed_tab(URL::URL const&, UnixDateTime closed_at = UnixDateTime::now()); void record_closed_window(Vector, size_t active_tab_index, UnixDateTime closed_at = UnixDateTime::now()); bool has_recently_closed_entries() const; Optional most_recently_closed_entry() const; Optional pop_most_recently_closed_entry(); Optional entry_for_url(URL::URL const&); Vector autocomplete_entries(StringView query, size_t limit = 8); Vector list_entries(StringView query = {}, size_t offset = 0, size_t limit = 50); void remove_entry_for_url(URL::URL const&); void remove_entries_for_same_site(URL::URL const&); void remove_entries_accessed_since(UnixDateTime since); private: struct Statements { Database::StatementID upsert_entry { 0 }; Database::StatementID update_title { 0 }; Database::StatementID update_favicon { 0 }; Database::StatementID get_entry { 0 }; Database::StatementID search_entries { 0 }; Database::StatementID list_entries { 0 }; Database::StatementID delete_entry { 0 }; Database::StatementID delete_entries_accessed_since { 0 }; Database::StatementID all_urls { 0 }; }; class StorageImpl { public: virtual ~StorageImpl() = default; virtual StringView name() = 0; virtual void record_visit(String const& url, Optional const& title, UnixDateTime visited_at) = 0; virtual void update_title(String const& url, String const& title) = 0; virtual void update_favicon(String const& url, String const& favicon_base64_png) = 0; virtual Optional entry_for_url(String const& url) = 0; virtual Vector autocomplete_entries(StringView title_query, StringView url_query, size_t limit) = 0; virtual Vector list_entries(StringView title_query, StringView url_query, size_t offset, size_t limit) = 0; virtual void remove_entry_for_url(String const& url) = 0; virtual void remove_entries_for_same_site(StringView site_key) = 0; virtual void remove_entries_accessed_since(UnixDateTime since) = 0; }; class TransientStorage : public StorageImpl { public: virtual ~TransientStorage() override = default; virtual StringView name() override { return "transient"sv; } virtual void record_visit(String const& url, Optional const& title, UnixDateTime visited_at) override; virtual void update_title(String const& url, String const& title) override; virtual void update_favicon(String const& url, String const& favicon_base64_png) override; virtual Optional entry_for_url(String const& url) override; virtual Vector autocomplete_entries(StringView title_query, StringView url_query, size_t limit) override; virtual Vector list_entries(StringView title_query, StringView url_query, size_t offset, size_t limit) override; virtual void remove_entry_for_url(String const& url) override; virtual void remove_entries_for_same_site(StringView site_key) override; virtual void remove_entries_accessed_since(UnixDateTime since) override; private: HashMap m_entries; }; class PersistedStorage : public StorageImpl { public: PersistedStorage(Database::Database&, Statements&&); virtual ~PersistedStorage() override; virtual StringView name() override { return "SQL"sv; } virtual void record_visit(String const& url, Optional const& title, UnixDateTime visited_at) override; virtual void update_title(String const& url, String const& title) override; virtual void update_favicon(String const& url, String const& favicon_base64_png) override; virtual Optional entry_for_url(String const& url) override; virtual Vector autocomplete_entries(StringView title_query, StringView url_query, size_t limit) override; virtual Vector list_entries(StringView title_query, StringView url_query, size_t offset, size_t limit) override; virtual void remove_entry_for_url(String const& url) override; virtual void remove_entries_for_same_site(StringView site_key) override; virtual void remove_entries_accessed_since(UnixDateTime since) override; private: Database::Database& m_database; Statements m_statements; }; explicit HistoryStore(NonnullOwnPtr&&, bool is_disabled = false); NonnullOwnPtr m_storage; Vector m_recently_closed_entries; bool m_is_disabled { false }; }; }