UI/Qt: Reduce flicker when populating autocomplete

Previously, autocomplete was cleared before the results for the current
query were retrieved. The new results would then be added when the
network request completed. This resulted in a noticable flicker. The
results are now updated when the request for the current query is
completed.

There is a small behavior change in that the query itself is no longer
included in the autocomplete dropdown unless the list would otherwise
be empty.

(cherry picked from commit c36a49b61eeaa7f892c4f2ca844891eb13295ffb)
This commit is contained in:
Tim Ledbetter 2024-06-27 13:44:18 +01:00 committed by Nico Weber
parent 73e0d101d9
commit 5439340808
2 changed files with 41 additions and 26 deletions

View file

@ -38,7 +38,7 @@ AutoComplete::AutoComplete(QWidget* parent)
});
}
ErrorOr<void> AutoComplete::parse_google_autocomplete(Vector<JsonValue> const& json)
ErrorOr<Vector<String>> AutoComplete::parse_google_autocomplete(Vector<JsonValue> const& json)
{
if (json.size() != 5)
return Error::from_string_view("Invalid JSON, expected 5 elements in array"sv);
@ -54,26 +54,28 @@ ErrorOr<void> AutoComplete::parse_google_autocomplete(Vector<JsonValue> const& j
if (query != m_query)
return Error::from_string_view("Invalid JSON, query does not match"sv);
for (auto& suggestion : suggestions_array) {
m_auto_complete_model->add(TRY(String::from_byte_string(suggestion.as_string())));
}
Vector<String> results;
results.ensure_capacity(suggestions_array.size());
for (auto& suggestion : suggestions_array)
results.unchecked_append(MUST(String::from_byte_string(suggestion.as_string())));
return {};
return results;
}
ErrorOr<void> AutoComplete::parse_duckduckgo_autocomplete(Vector<JsonValue> const& json)
ErrorOr<Vector<String>> AutoComplete::parse_duckduckgo_autocomplete(Vector<JsonValue> const& json)
{
Vector<String> results;
for (auto const& suggestion : json) {
auto maybe_value = suggestion.as_object().get("phrase"sv);
if (!maybe_value.has_value())
continue;
m_auto_complete_model->add(TRY(String::from_byte_string(maybe_value->as_string())));
results.append(MUST(String::from_byte_string(maybe_value->as_string())));
}
return {};
return results;
}
ErrorOr<void> AutoComplete::parse_yahoo_autocomplete(JsonObject const& json)
ErrorOr<Vector<String>> AutoComplete::parse_yahoo_autocomplete(JsonObject const& json)
{
if (!json.get("q"sv).has_value() || !json.get("q"sv)->is_string())
return Error::from_string_view("Invalid JSON, expected \"q\" to be a string"sv);
@ -86,6 +88,8 @@ ErrorOr<void> AutoComplete::parse_yahoo_autocomplete(JsonObject const& json)
if (query != m_query)
return Error::from_string_view("Invalid JSON, query does not match"sv);
Vector<String> results;
results.ensure_capacity(suggestions_object.size());
for (auto& suggestion_object : suggestions_object) {
if (!suggestion_object.is_object())
return Error::from_string_view("Invalid JSON, expected value to be an object"sv);
@ -94,10 +98,10 @@ ErrorOr<void> AutoComplete::parse_yahoo_autocomplete(JsonObject const& json)
if (!suggestion.get("k"sv).has_value() || !suggestion.get("k"sv)->is_string())
return Error::from_string_view("Invalid JSON, expected \"k\" to be a string"sv);
m_auto_complete_model->add(TRY(String::from_byte_string(suggestion.get("k"sv)->as_string())));
};
results.unchecked_append(MUST(String::from_byte_string(suggestion.get("k"sv)->as_string())));
}
return {};
return results;
}
ErrorOr<void> AutoComplete::got_network_response(QNetworkReply* reply)
@ -109,16 +113,23 @@ ErrorOr<void> AutoComplete::got_network_response(QNetworkReply* reply)
auto json = TRY(parser.parse());
auto engine_name = Settings::the()->autocomplete_engine().name;
if (engine_name == "Google")
return parse_google_autocomplete(json.as_array().values());
Vector<String> results;
if (engine_name == "Google") {
results = TRY(parse_google_autocomplete(json.as_array().values()));
} else if (engine_name == "DuckDuckGo") {
results = TRY(parse_duckduckgo_autocomplete(json.as_array().values()));
} else if (engine_name == "Yahoo")
results = TRY(parse_yahoo_autocomplete(json.as_object()));
else {
return Error::from_string_view("Invalid engine name"sv);
}
if (engine_name == "DuckDuckGo")
return parse_duckduckgo_autocomplete(json.as_array().values());
if (results.is_empty()) {
results.append(m_query);
}
if (engine_name == "Yahoo")
return parse_yahoo_autocomplete(json.as_object());
return Error::from_string_view("Invalid engine name"sv);
m_auto_complete_model->replace_suggestions(move(results));
return {};
}
String AutoComplete::auto_complete_url_from_query(StringView query)
@ -138,9 +149,6 @@ void AutoComplete::get_search_suggestions(String search_string)
if (m_reply)
m_reply->abort();
m_auto_complete_model->clear();
m_auto_complete_model->add(m_query);
QNetworkRequest request { QUrl(qstring_from_ak_string(auto_complete_url_from_query(m_query))) };
m_reply = m_manager->get(request);
}

View file

@ -45,6 +45,13 @@ public:
endResetModel();
}
void replace_suggestions(Vector<String> suggestions)
{
beginInsertRows({}, m_suggestions.size(), m_suggestions.size());
m_suggestions = suggestions;
endInsertRows();
}
private:
AK::Vector<String> m_suggestions;
};
@ -71,9 +78,9 @@ private:
ErrorOr<void> got_network_response(QNetworkReply* reply);
ErrorOr<void> parse_google_autocomplete(Vector<JsonValue> const&);
ErrorOr<void> parse_duckduckgo_autocomplete(Vector<JsonValue> const&);
ErrorOr<void> parse_yahoo_autocomplete(JsonObject const&);
ErrorOr<Vector<String>> parse_google_autocomplete(Vector<JsonValue> const&);
ErrorOr<Vector<String>> parse_duckduckgo_autocomplete(Vector<JsonValue> const&);
ErrorOr<Vector<String>> parse_yahoo_autocomplete(JsonObject const&);
QNetworkAccessManager* m_manager;
AutoCompleteModel* m_auto_complete_model;