Adding initial search view.
This commit is contained in:
parent
c96742dcf4
commit
31850456aa
@ -30,6 +30,10 @@ mg_backend_readmng_new (void);
|
||||
GListStore *
|
||||
mg_backend_readmng_get_featured_manga (MgBackendReadmng *self);
|
||||
|
||||
GListStore *
|
||||
mg_backend_readmng_search (MgBackendReadmng *self,
|
||||
const char *search_query);
|
||||
|
||||
void
|
||||
mg_backend_readmng_retrieve_manga_details (MgBackendReadmng *self,
|
||||
MgManga *manga);
|
||||
|
@ -27,6 +27,6 @@ mg_util_regex_splitted_string_free (MgUtilRegex *self,
|
||||
struct SplittedString *splitted_string);
|
||||
char *
|
||||
mg_util_regex_match_1 (MgUtilRegex *self,
|
||||
char *re_str, char *subject);
|
||||
const char *re_str, const char *subject);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -9,7 +9,17 @@ G_DECLARE_FINAL_TYPE (MgUtilSoup, mg_util_soup, MG, UTIL_SOUP, GObject)
|
||||
MgUtilSoup *
|
||||
mg_util_soup_new ();
|
||||
|
||||
typedef struct {
|
||||
char *key;
|
||||
char *value;
|
||||
} SoupParam;
|
||||
|
||||
char *
|
||||
mg_util_soup_get_request (MgUtilSoup *self, const char *const url, gsize *size_response_text);
|
||||
char *
|
||||
mg_util_soup_post_request_url_encoded (MgUtilSoup *self,
|
||||
const char *url, SoupParam *body, gsize body_len,
|
||||
SoupParam *headers, gsize headers_len,
|
||||
gsize *size_response_text);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <adwaita.h>
|
||||
|
||||
typedef struct {
|
||||
AdwHeaderBar *header;
|
||||
AdwLeaflet *views_leaflet;
|
||||
|
6
include/openmg/view/search.h
Normal file
6
include/openmg/view/search.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <openmg/view/controls.h>
|
||||
|
||||
GtkWidget *
|
||||
create_search_view (ControlsAdwaita *controls);
|
@ -9,7 +9,8 @@ openmgdeps = [
|
||||
dependency('libxml-2.0'),
|
||||
dependency('libpcre2-8'),
|
||||
dependency('gio-2.0'),
|
||||
dependency('sqlite3')
|
||||
dependency('sqlite3'),
|
||||
dependency('json-glib-1.0'),
|
||||
]
|
||||
|
||||
sources = [
|
||||
@ -30,6 +31,7 @@ sources = [
|
||||
'src/database.c',
|
||||
'src/database/statement.c',
|
||||
'src/view/explore.c',
|
||||
'src/view/search.c',
|
||||
'src/main.c',
|
||||
]
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <json-glib/json-glib.h>
|
||||
|
||||
#include <libxml/HTMLparser.h>
|
||||
|
||||
#ifndef PCRE2_CODE_UNIT_WIDTH
|
||||
@ -63,6 +65,8 @@ static MgMangaChapter *
|
||||
mg_backend_readmng_loop_li_chapter (
|
||||
MgBackendReadmng *self,
|
||||
xmlNodePtr li);
|
||||
static char *
|
||||
mg_backend_readmng_fetch_search (MgBackendReadmng *self, const char *search_query);
|
||||
static GListModel *
|
||||
mg_backend_readmng_parse_page (MgBackendReadmng *self,
|
||||
xmlDocPtr html_document);
|
||||
@ -92,6 +96,8 @@ static GListStore *
|
||||
mg_backend_readmng_parse_main_page (MgBackendReadmng *self, const xmlDocPtr html_document);
|
||||
static xmlDocPtr
|
||||
mg_backend_readmng_fetch_xml_main_page (MgBackendReadmng *self);
|
||||
static char *
|
||||
mg_backend_readmng_get_id_manga_link_from_string (MgBackendReadmng *self, const char *url);
|
||||
|
||||
MgBackendReadmng *
|
||||
mg_backend_readmng_new(void) {
|
||||
@ -226,6 +232,113 @@ mg_backend_readmng_fetch_page_url (MgBackendReadmng *self,
|
||||
return document;
|
||||
}
|
||||
|
||||
GListStore *
|
||||
mg_backend_readmng_search (MgBackendReadmng *self,
|
||||
const char *search_query) {
|
||||
char *response = mg_backend_readmng_fetch_search (self, search_query);
|
||||
JsonParser *parser = json_parser_new ();
|
||||
GListStore *mangas = g_list_store_new(MG_TYPE_MANGA);
|
||||
GError *error = NULL;
|
||||
JsonNode *root = NULL;
|
||||
JsonArray *mangas_json_array = NULL;
|
||||
guint mangas_json_array_len = 0;
|
||||
|
||||
json_parser_load_from_data (parser, response, -1, &error);
|
||||
if (error) {
|
||||
g_warning ("Unable to parse json: %s.", error->message);
|
||||
g_clear_error (&error);
|
||||
goto cleanup_mg_backend_readmng_search;
|
||||
}
|
||||
root = json_parser_get_root (parser);
|
||||
if (json_node_get_node_type (root) != JSON_NODE_ARRAY) {
|
||||
goto cleanup_mg_backend_readmng_search;
|
||||
}
|
||||
mangas_json_array = json_node_get_array (root);
|
||||
mangas_json_array_len = json_array_get_length (
|
||||
mangas_json_array);
|
||||
for (guint i = 0; i < mangas_json_array_len; i++) {
|
||||
JsonObject *manga_json_object =
|
||||
json_array_get_object_element (mangas_json_array, i);
|
||||
char *id_manga = NULL;
|
||||
const char *url = json_object_get_string_member
|
||||
(manga_json_object, "url");
|
||||
const char *title = json_object_get_string_member
|
||||
(manga_json_object, "title");
|
||||
const char *image = json_object_get_string_member
|
||||
(manga_json_object, "image");
|
||||
|
||||
id_manga = mg_backend_readmng_get_id_manga_link_from_string (self, url);
|
||||
g_list_store_append (mangas, mg_manga_new (image, title, id_manga));
|
||||
|
||||
pcre2_substring_free ((PCRE2_UCHAR8 *) id_manga);
|
||||
}
|
||||
cleanup_mg_backend_readmng_search:
|
||||
g_clear_object (&parser);
|
||||
g_free (response);
|
||||
response = NULL;
|
||||
return mangas;
|
||||
}
|
||||
|
||||
static char *
|
||||
mg_backend_readmng_fetch_search (MgBackendReadmng *self, const char *search_query) {
|
||||
MgUtilSoup *util_soup;
|
||||
MgUtilString *string_util;
|
||||
|
||||
char *request_url;
|
||||
|
||||
size_t request_url_len;
|
||||
size_t response_len = 0;
|
||||
|
||||
util_soup = mg_util_soup_new ();
|
||||
string_util = mg_util_string_new ();
|
||||
request_url_len = snprintf ( NULL, 0, "%s/%s/", self->base_url, "service/search");
|
||||
request_url = mg_util_string_alloc_string (string_util, request_url_len);
|
||||
snprintf ( request_url, request_url_len+1, "%s/%s/", self->base_url, "service/search");
|
||||
|
||||
SoupParam headers[] = {
|
||||
{
|
||||
.key = "Accept",
|
||||
.value = "application/json, text/javascript, */*; q=0.01"
|
||||
},
|
||||
{
|
||||
.key = "Content-Type",
|
||||
.value = "application/x-www-form-urlencoded; charset=UTF-8"
|
||||
},
|
||||
{
|
||||
.key = "X-Requested-With",
|
||||
.value = "XMLHttpRequest"
|
||||
}
|
||||
};
|
||||
|
||||
char *phrase = g_malloc (strlen (search_query) + 1);
|
||||
snprintf ( phrase, strlen (search_query) + 1, "%s", search_query);
|
||||
|
||||
SoupParam body[] = {
|
||||
{
|
||||
.key = "dataType",
|
||||
.value = "json"
|
||||
},
|
||||
{
|
||||
.key = "phrase",
|
||||
.value = phrase
|
||||
}
|
||||
};
|
||||
|
||||
size_t headers_len = sizeof headers / sizeof *headers;
|
||||
size_t body_len = sizeof body / sizeof *body;
|
||||
|
||||
char *text_response = mg_util_soup_post_request_url_encoded (util_soup,
|
||||
request_url, body, body_len, headers, headers_len, &response_len);
|
||||
|
||||
g_free (request_url);
|
||||
g_free (phrase);
|
||||
request_url = NULL;
|
||||
g_clear_object (&util_soup);
|
||||
g_clear_object (&string_util);
|
||||
|
||||
return text_response;
|
||||
}
|
||||
|
||||
|
||||
GListStore *
|
||||
mg_backend_readmng_get_featured_manga (MgBackendReadmng *self) {
|
||||
@ -402,7 +515,6 @@ mg_backend_readmng_fetch_xml_details (MgBackendReadmng *self,
|
||||
size_t request_url_len;
|
||||
size_t response_len = 0;
|
||||
|
||||
|
||||
util_soup = mg_util_soup_new ();
|
||||
string_util = mg_util_string_new ();
|
||||
manga_id = mg_manga_get_id (manga);
|
||||
@ -573,13 +685,18 @@ mg_backend_readmng_find_a_link_chapter (MgBackendReadmng *self,
|
||||
|
||||
static char *
|
||||
mg_backend_readmng_get_id_manga_link (MgBackendReadmng *self, xmlNodePtr a) {
|
||||
char *re_str = "readmng\\.com/([^/]+)";
|
||||
MgUtilXML *xml_utils = self->xml_utils;
|
||||
MgUtilRegex *regex_util = mg_util_regex_new ();
|
||||
char *href = mg_util_xml_get_attr (xml_utils, a, "href");
|
||||
char *result = mg_util_regex_match_1 (regex_util, re_str, href);
|
||||
|
||||
char *result = mg_backend_readmng_get_id_manga_link_from_string (self, href);
|
||||
g_free (href);
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *
|
||||
mg_backend_readmng_get_id_manga_link_from_string (MgBackendReadmng *self, const char *url) {
|
||||
MgUtilRegex *regex_util = mg_util_regex_new ();
|
||||
char *re_str = "readmng\\.com/([^/]+)";
|
||||
char *result = mg_util_regex_match_1 (regex_util, re_str, url);
|
||||
g_clear_object (®ex_util);
|
||||
return result;
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ cleanup_iterate_string_to_split:
|
||||
|
||||
char *
|
||||
mg_util_regex_match_1 (MgUtilRegex *self,
|
||||
char *re_str, char *subject) {
|
||||
const char *re_str, const char *subject) {
|
||||
pcre2_code *re;
|
||||
pcre2_match_data *match_data;
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libsoup/soup.h>
|
||||
|
||||
#include <openmg/util/soup.h>
|
||||
@ -23,6 +26,7 @@ mg_util_soup_class_init (MgUtilSoupClass *class) {
|
||||
static void
|
||||
mg_util_soup_init (MgUtilSoup *self) {
|
||||
}
|
||||
|
||||
char *
|
||||
mg_util_soup_get_request (MgUtilSoup *self, const char *url, gsize *size_response_text) {
|
||||
SoupSession *soup_session;
|
||||
@ -53,6 +57,101 @@ mg_util_soup_get_request (MgUtilSoup *self, const char *url, gsize *size_respons
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
char *
|
||||
mg_util_soup_post_request_url_encoded (MgUtilSoup *self,
|
||||
const char *url, SoupParam *body, gsize body_len,
|
||||
SoupParam *headers, gsize headers_len,
|
||||
gsize *size_response_text) {
|
||||
SoupSession *soup_session;
|
||||
SoupMessage *msg;
|
||||
SoupMessageBody *request_body;
|
||||
SoupMessageHeaders *request_headers;
|
||||
|
||||
GValue response = G_VALUE_INIT;
|
||||
GValue request = G_VALUE_INIT;
|
||||
GValue request_headers_value = G_VALUE_INIT;
|
||||
|
||||
*size_response_text = 0;
|
||||
|
||||
g_value_init (&response, G_TYPE_BYTES);
|
||||
g_value_init (&request, SOUP_TYPE_MESSAGE_BODY);
|
||||
g_value_init (&request_headers_value,
|
||||
SOUP_TYPE_MESSAGE_HEADERS);
|
||||
|
||||
soup_session = soup_session_new ();
|
||||
msg = soup_message_new ("POST", url);
|
||||
g_object_get_property (
|
||||
G_OBJECT (msg),
|
||||
"request-body",
|
||||
&request);
|
||||
|
||||
g_object_get_property (
|
||||
G_OBJECT (msg),
|
||||
"request-headers",
|
||||
&request_headers_value);
|
||||
|
||||
soup_message_set_request (msg,
|
||||
"application/x-www-form-urlencoded; charset=UTF-8",
|
||||
SOUP_MEMORY_COPY, "", 1);
|
||||
|
||||
request_body = g_value_peek_pointer (&request);
|
||||
request_headers = g_value_peek_pointer (
|
||||
&request_headers_value);
|
||||
|
||||
for (int i = 0; i < body_len; i++) {
|
||||
char *key = g_uri_escape_string (body[i].key,
|
||||
NULL, false);
|
||||
size_t key_len = strlen (key) + 1;
|
||||
char *value = g_uri_escape_string (body[i].value,
|
||||
NULL, false);
|
||||
size_t value_len = strlen (value) + 1;
|
||||
|
||||
if (body_len) {
|
||||
soup_message_body_append (request_body,
|
||||
SOUP_MEMORY_COPY, "&", 1);
|
||||
}
|
||||
|
||||
soup_message_body_append (request_body,
|
||||
SOUP_MEMORY_COPY, key, key_len);
|
||||
soup_message_body_append (request_body,
|
||||
SOUP_MEMORY_COPY, "=", 1);
|
||||
soup_message_body_append (request_body,
|
||||
SOUP_MEMORY_COPY, value, value_len);
|
||||
|
||||
g_free (key);
|
||||
g_free (value);
|
||||
}
|
||||
soup_message_body_append (request_body,
|
||||
SOUP_MEMORY_COPY, "", 1);
|
||||
|
||||
for (int i = 0; i < headers_len; i++) {
|
||||
soup_message_headers_append (request_headers,
|
||||
headers[i].key,
|
||||
headers[i].value);
|
||||
}
|
||||
|
||||
soup_session_send_message (soup_session, msg);
|
||||
g_object_get_property(
|
||||
G_OBJECT (msg),
|
||||
"response-body-data",
|
||||
&response);
|
||||
|
||||
const char *html_response = g_bytes_get_data ((GBytes *)
|
||||
g_value_peek_pointer (&response),
|
||||
size_response_text);
|
||||
|
||||
char *return_value = mg_util_soup_copy_binary_data(self, html_response, *size_response_text);
|
||||
|
||||
g_value_unset (&response);
|
||||
g_value_unset (&request);
|
||||
|
||||
g_clear_object (&soup_session);
|
||||
g_clear_object (&msg);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
static char *
|
||||
mg_util_soup_copy_binary_data (MgUtilSoup *self, const char *input, size_t size) {
|
||||
char *response = NULL;
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <openmg/view/controls.h>
|
||||
#include <openmg/view/explore.h>
|
||||
#include <openmg/view/search.h>
|
||||
|
||||
static AdwHeaderBar *
|
||||
create_headerbar (GtkBox *box, ControlsAdwaita *controls, GtkButton **out_previous);
|
||||
@ -15,6 +16,8 @@ go_back_view (GtkButton *previous, gpointer user_data);
|
||||
typedef void (*swipe_back_t)(AdwLeaflet *, gboolean);
|
||||
static AdwLeaflet *
|
||||
create_explore_leaflet (ControlsAdwaita *controls, swipe_back_t swipe_back);
|
||||
static AdwLeaflet *
|
||||
create_search_leaflet (ControlsAdwaita *controls, swipe_back_t swipe_back);
|
||||
|
||||
static void
|
||||
activate (AdwApplication *app,
|
||||
@ -29,6 +32,7 @@ activate (AdwApplication *app,
|
||||
ControlsAdwaita *controls = g_malloc (sizeof *controls);
|
||||
GtkButton *previous = NULL;
|
||||
AdwLeaflet *views_leaflet_explore;
|
||||
AdwLeaflet *views_leaflet_search;
|
||||
AdwHeaderBar *header_bar;
|
||||
|
||||
swipe_back_t swipe_back = (swipe_back_t) dlsym
|
||||
@ -45,6 +49,7 @@ activate (AdwApplication *app,
|
||||
|
||||
|
||||
views_leaflet_explore = create_explore_leaflet (controls, swipe_back);
|
||||
views_leaflet_search = create_search_leaflet (controls, swipe_back);
|
||||
header_bar = create_headerbar (box, controls, &previous);
|
||||
controls->header = header_bar;
|
||||
controls->previous = previous;
|
||||
@ -52,12 +57,32 @@ activate (AdwApplication *app,
|
||||
AdwViewStackPage *explore_page = adw_view_stack_add_titled (view_stack, GTK_WIDGET (views_leaflet_explore),
|
||||
"explore",
|
||||
"Explore");
|
||||
AdwViewStackPage *search_page = adw_view_stack_add_titled (view_stack, GTK_WIDGET (views_leaflet_search),
|
||||
"search",
|
||||
"Search");
|
||||
|
||||
adw_view_stack_page_set_icon_name (explore_page, "view-list-symbolic");
|
||||
adw_view_stack_page_set_icon_name (search_page, "system-search-symbolic");
|
||||
|
||||
gtk_box_append (box, GTK_WIDGET (view_stack));
|
||||
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
static AdwLeaflet *
|
||||
create_search_leaflet (ControlsAdwaita *controls, swipe_back_t swipe_back) {
|
||||
AdwLeaflet *views_leaflet = ADW_LEAFLET (adw_leaflet_new ());
|
||||
GtkWidget *search_view;
|
||||
swipe_back (views_leaflet, 1);
|
||||
search_view = create_search_view (controls);
|
||||
|
||||
adw_leaflet_append (views_leaflet, search_view);
|
||||
|
||||
adw_leaflet_set_can_unfold (views_leaflet, false);
|
||||
|
||||
return views_leaflet;
|
||||
}
|
||||
|
||||
static AdwLeaflet *
|
||||
create_explore_leaflet (ControlsAdwaita *controls, swipe_back_t swipe_back) {
|
||||
AdwLeaflet *views_leaflet_explore = ADW_LEAFLET (adw_leaflet_new ());
|
||||
@ -75,8 +100,7 @@ create_explore_leaflet (ControlsAdwaita *controls, swipe_back_t swipe_back) {
|
||||
|
||||
static GtkBox *
|
||||
create_main_box (AdwApplicationWindow *window) {
|
||||
GtkWidget *box = gtk_box_new(
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL,
|
||||
10);
|
||||
adw_application_window_set_content(
|
||||
window,
|
||||
|
11
src/view/search.c
Normal file
11
src/view/search.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <openmg/view/search.h>
|
||||
|
||||
GtkWidget *
|
||||
create_search_view (ControlsAdwaita *controls) {
|
||||
GtkWidget *search_view = gtk_box_new (
|
||||
GTK_ORIENTATION_VERTICAL, 10);
|
||||
|
||||
GtkWidget *search_entry = gtk_entry_new ();
|
||||
gtk_box_append (GTK_BOX (search_view), search_entry);;
|
||||
return search_view;
|
||||
}
|
Loading…
Reference in New Issue
Block a user