- Add FeedItem, Feed, FeedSubscription models - Add SearchResult, SearchFilters, SearchQuery models - Add NotificationPreferences, ReadingPreferences models - Implement JSON serialization/deserialization for all models - Add equality comparison methods - Following GNOME HIG naming conventions - Build system configured with Meson/Ninja
209 lines
5.9 KiB
Vala
209 lines
5.9 KiB
Vala
/*
|
|
* SearchResult.vala
|
|
*
|
|
* Represents a search result item from the feed database.
|
|
* Following GNOME HIG naming conventions and Vala/GObject patterns.
|
|
*/
|
|
|
|
/**
|
|
* SearchResultType - Type of search result
|
|
*/
|
|
public enum RSSuper.SearchResultType {
|
|
ARTICLE,
|
|
FEED
|
|
}
|
|
|
|
/**
|
|
* SearchResult - Represents a single search result
|
|
*/
|
|
public class RSSuper.SearchResult : Object {
|
|
public string id { get; set; }
|
|
public SearchResultType result_type { get; set; }
|
|
public string title { get; set; }
|
|
public string? snippet { get; set; }
|
|
public string? link { get; set; }
|
|
public string? feed_title { get; set; }
|
|
public string? published { get; set; }
|
|
public double score { get; set; }
|
|
|
|
/**
|
|
* Default constructor
|
|
*/
|
|
public SearchResult() {
|
|
this.id = "";
|
|
this.result_type = SearchResultType.ARTICLE;
|
|
this.title = "";
|
|
this.score = 0.0;
|
|
}
|
|
|
|
/**
|
|
* Constructor with initial values
|
|
*/
|
|
public SearchResult.with_values(string id, SearchResultType type, string title,
|
|
string? snippet = null, string? link = null,
|
|
string? feed_title = null, string? published = null,
|
|
double score = 0.0) {
|
|
this.id = id;
|
|
this.result_type = type;
|
|
this.title = title;
|
|
this.snippet = snippet;
|
|
this.link = link;
|
|
this.feed_title = feed_title;
|
|
this.published = published;
|
|
this.score = score;
|
|
}
|
|
|
|
/**
|
|
* Get type as string
|
|
*/
|
|
public string get_type_string() {
|
|
switch (this.result_type) {
|
|
case SearchResultType.ARTICLE:
|
|
return "article";
|
|
case SearchResultType.FEED:
|
|
return "feed";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse type from string
|
|
*/
|
|
public static SearchResultType type_from_string(string str) {
|
|
switch (str) {
|
|
case "article":
|
|
return SearchResultType.ARTICLE;
|
|
case "feed":
|
|
return SearchResultType.FEED;
|
|
default:
|
|
return SearchResultType.ARTICLE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Serialize to JSON string
|
|
*/
|
|
public string to_json_string() {
|
|
var sb = new StringBuilder();
|
|
sb.append("{");
|
|
sb.append("\"id\":\"");
|
|
sb.append(this.id);
|
|
sb.append("\",\"type\":\"");
|
|
sb.append(this.get_type_string());
|
|
sb.append("\",\"title\":\"");
|
|
sb.append(this.title);
|
|
sb.append("\"");
|
|
|
|
if (this.snippet != null) {
|
|
sb.append(",\"snippet\":\"");
|
|
sb.append(this.snippet);
|
|
sb.append("\"");
|
|
}
|
|
if (this.link != null) {
|
|
sb.append(",\"link\":\"");
|
|
sb.append(this.link);
|
|
sb.append("\"");
|
|
}
|
|
if (this.feed_title != null) {
|
|
sb.append(",\"feedTitle\":\"");
|
|
sb.append(this.feed_title);
|
|
sb.append("\"");
|
|
}
|
|
if (this.published != null) {
|
|
sb.append(",\"published\":\"");
|
|
sb.append(this.published);
|
|
sb.append("\"");
|
|
}
|
|
if (this.score != 0.0) {
|
|
sb.append(",\"score\":%f".printf(this.score));
|
|
}
|
|
|
|
sb.append("}");
|
|
return sb.str;
|
|
}
|
|
|
|
/**
|
|
* Deserialize from JSON string
|
|
*/
|
|
public static SearchResult? from_json_string(string json_string) {
|
|
var parser = new Json.Parser();
|
|
try {
|
|
if (!parser.load_from_data(json_string)) {
|
|
return null;
|
|
}
|
|
} catch (Error e) {
|
|
warning("Failed to parse JSON: %s", e.message);
|
|
return null;
|
|
}
|
|
|
|
return from_json_node(parser.get_root());
|
|
}
|
|
|
|
/**
|
|
* Deserialize from Json.Node
|
|
*/
|
|
public static SearchResult? from_json_node(Json.Node node) {
|
|
if (node.get_node_type() != Json.NodeType.OBJECT) {
|
|
return null;
|
|
}
|
|
|
|
var obj = node.get_object();
|
|
|
|
if (!obj.has_member("id") || !obj.has_member("type") || !obj.has_member("title")) {
|
|
return null;
|
|
}
|
|
|
|
var result = new SearchResult();
|
|
result.id = obj.get_string_member("id");
|
|
result.result_type = SearchResult.type_from_string(obj.get_string_member("type"));
|
|
result.title = obj.get_string_member("title");
|
|
|
|
if (obj.has_member("snippet")) {
|
|
result.snippet = obj.get_string_member("snippet");
|
|
}
|
|
if (obj.has_member("link")) {
|
|
result.link = obj.get_string_member("link");
|
|
}
|
|
if (obj.has_member("feedTitle")) {
|
|
result.feed_title = obj.get_string_member("feedTitle");
|
|
}
|
|
if (obj.has_member("published")) {
|
|
result.published = obj.get_string_member("published");
|
|
}
|
|
if (obj.has_member("score")) {
|
|
result.score = obj.get_double_member("score");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Equality comparison
|
|
*/
|
|
public bool equals(SearchResult? other) {
|
|
if (other == null) {
|
|
return false;
|
|
}
|
|
|
|
return this.id == other.id &&
|
|
this.result_type == other.result_type &&
|
|
this.title == other.title &&
|
|
this.snippet == other.snippet &&
|
|
this.link == other.link &&
|
|
this.feed_title == other.feed_title &&
|
|
this.published == other.published &&
|
|
this.score == other.score;
|
|
}
|
|
|
|
/**
|
|
* Get a human-readable summary
|
|
*/
|
|
public string get_summary() {
|
|
if (this.feed_title != null) {
|
|
return "[%s] %s - %s".printf(this.get_type_string(), this.feed_title, this.title);
|
|
}
|
|
return "[%s] %s".printf(this.get_type_string(), this.title);
|
|
}
|
|
}
|