forked from sergiotarxz/mangareader
Merge branch 'main' into main
This commit is contained in:
commit
5c00c7e09c
@ -1,2 +1,5 @@
|
|||||||
Sergiotarxz sergiotarxz@posteo.net Project leader and developer [Gitea](https://gitea.sergiotarxz.freemyip.com/sergiotarxz)
|
Sergiotarxz sergiotarxz@posteo.net Project leader and developer. [Gitea](https://gitea.sergiotarxz.freemyip.com/sergiotarxz)
|
||||||
Germe.db FOSSgerme.deb@tuta.io Author of the icon openmg.svg. [sr.ht](https://sr.ht/~germe-fur/)
|
|
||||||
|
Germe.db FOSSgerme.deb@tuta.io Designer and icons creator. [sr.ht](https://sr.ht/~germe-fur/)
|
||||||
|
|
||||||
|
Endes endes@disroot.org Developer. [Github](https://github.com/endes0)
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Installing the app.
|
## Installing the app.
|
||||||
|
|
||||||
|
First fine tune the options in `me.sergiotarxz.openmg.json` for
|
||||||
|
meson you want to have, for example preview images, complete list is
|
||||||
|
on `meson_options.txt`
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
flatpak --user remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo
|
flatpak --user remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo
|
||||||
flatpak install org.gnome.Sdk//master
|
flatpak install org.gnome.Sdk//master
|
||||||
@ -15,3 +19,7 @@ flatpak-builder --install --user build me.sergiotarxz.openmg.yml me.sergiotarxz.
|
|||||||
```shell
|
```shell
|
||||||
flatpak run me.sergiotarxz.openmg
|
flatpak run me.sergiotarxz.openmg
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Donations welcome:
|
||||||
|
|
||||||
|
btc: `bc1q0apxdedrm5vjn3zr0hxswnruk2x2uecwqrusmj`
|
||||||
|
@ -9,6 +9,9 @@ typedef struct {
|
|||||||
AdwHeaderBar *header;
|
AdwHeaderBar *header;
|
||||||
AdwLeaflet *views_leaflet;
|
AdwLeaflet *views_leaflet;
|
||||||
AdwViewStack *view_stack;
|
AdwViewStack *view_stack;
|
||||||
|
GCancellable **image_threads;
|
||||||
|
size_t image_threads_len;
|
||||||
|
bool avoid_list_image_downloads;
|
||||||
GtkButton *previous;
|
GtkButton *previous;
|
||||||
gboolean is_set_previous;
|
gboolean is_set_previous;
|
||||||
} ControlsAdwaita;
|
} ControlsAdwaita;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
void
|
GtkPicture *
|
||||||
create_picture_from_url (const char *const url, gint picture_size,
|
create_picture_from_url (const char *const url, gint picture_size,
|
||||||
GAsyncReadyCallback ready, gpointer source_object,
|
GAsyncReadyCallback ready, gpointer source_object,
|
||||||
gpointer callback_data);
|
gpointer callback_data, bool do_not_download);
|
||||||
|
30
me.sergiotarxz.openmg.json
Normal file
30
me.sergiotarxz.openmg.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"app-id": "me.sergiotarxz.openmg",
|
||||||
|
"runtime": "org.gnome.Platform",
|
||||||
|
"runtime-version": "master",
|
||||||
|
"sdk": "org.gnome.Sdk",
|
||||||
|
"command": "openmg",
|
||||||
|
"finish-args": [
|
||||||
|
"--share=ipc",
|
||||||
|
"--socket=x11",
|
||||||
|
"--socket=wayland",
|
||||||
|
"--socket=session-bus",
|
||||||
|
"--share=network",
|
||||||
|
"--device=dri"
|
||||||
|
],
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"name": "openmg",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [
|
||||||
|
"-Dimages=true"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "dir",
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
app-id: me.sergiotarxz.openmg
|
|
||||||
runtime: org.gnome.Platform
|
|
||||||
runtime-version: master
|
|
||||||
sdk: org.gnome.Sdk
|
|
||||||
sdk-version: master
|
|
||||||
command: openmg
|
|
||||||
finish-args:
|
|
||||||
- "--share=ipc"
|
|
||||||
- "--socket=x11"
|
|
||||||
- "--socket=wayland"
|
|
||||||
- "--socket=session-bus"
|
|
||||||
- "--share=network"
|
|
||||||
- "--device=dri"
|
|
||||||
modules:
|
|
||||||
- name: openmg
|
|
||||||
buildsystem: meson
|
|
||||||
sources:
|
|
||||||
- type: dir
|
|
||||||
path: .
|
|
16
meson.build
16
meson.build
@ -36,14 +36,26 @@ sources = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
link_arguments = [
|
link_arguments = [
|
||||||
'-ldl',
|
|
||||||
'-lm'
|
'-lm'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
images_on_lists = get_option('images')
|
||||||
|
is_windows = get_option('windows')
|
||||||
|
|
||||||
|
if not is_windows
|
||||||
|
link_arguments += ['-ldl']
|
||||||
|
endif
|
||||||
|
|
||||||
|
cArgs = []
|
||||||
|
if images_on_lists
|
||||||
|
cArgs += ['-DLIST_IMAGES']
|
||||||
|
endif
|
||||||
|
|
||||||
executable('openmg',
|
executable('openmg',
|
||||||
sources,
|
sources,
|
||||||
dependencies : openmgdeps,
|
dependencies : openmgdeps,
|
||||||
include_directories : inc,
|
include_directories : inc,
|
||||||
install : true,
|
install : true,
|
||||||
link_args : link_arguments
|
link_args : link_arguments,
|
||||||
|
c_args: cArgs
|
||||||
)
|
)
|
||||||
|
2
meson_options.txt
Normal file
2
meson_options.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
option('images', type : 'boolean', value : true)
|
||||||
|
option('windows', type : 'boolean', value : false)
|
36
openmg.supp
Normal file
36
openmg.supp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#
|
||||||
|
# Valgrind suppression file for mangareader.
|
||||||
|
# Warning: This file is very generic, so a real memory leak might be suppressed.
|
||||||
|
# Also, some false positives are still captured
|
||||||
|
#
|
||||||
|
# Format specification:
|
||||||
|
# http://valgrind.org/docs/manual/manual-core.html#manual-core.suppress
|
||||||
|
#
|
||||||
|
{
|
||||||
|
gtk4
|
||||||
|
Memcheck:Leak
|
||||||
|
...
|
||||||
|
obj:/usr/lib/x86_64-linux-gnu/libgtk-4.so.1.600.0
|
||||||
|
...
|
||||||
|
}
|
||||||
|
{
|
||||||
|
glib
|
||||||
|
Memcheck:Leak
|
||||||
|
...
|
||||||
|
obj:/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7100.0
|
||||||
|
...
|
||||||
|
}
|
||||||
|
{
|
||||||
|
fontconfig
|
||||||
|
Memcheck:Leak
|
||||||
|
...
|
||||||
|
obj:/usr/lib/x86_64-linux-gnu/libfontconfig.so.1.12.0
|
||||||
|
...
|
||||||
|
}
|
||||||
|
{
|
||||||
|
gallium
|
||||||
|
Memcheck:Leak
|
||||||
|
...
|
||||||
|
obj:/usr/lib/x86_64-linux-gnu/GL/default/lib/dri/libgallium_dri.so
|
||||||
|
...
|
||||||
|
}
|
1
sqlite
1
sqlite
@ -1 +0,0 @@
|
|||||||
Subproject commit 855a165fecc25da50cb20525ddf5b9e60a67d18f
|
|
@ -66,7 +66,8 @@ mg_backend_readmng_loop_li_chapter (
|
|||||||
MgBackendReadmng *self,
|
MgBackendReadmng *self,
|
||||||
xmlNodePtr li);
|
xmlNodePtr li);
|
||||||
static char *
|
static char *
|
||||||
mg_backend_readmng_fetch_search (MgBackendReadmng *self, const char *search_query);
|
mg_backend_readmng_fetch_search (MgBackendReadmng *self,
|
||||||
|
const char *search_query, size_t *response_len);
|
||||||
static GListModel *
|
static GListModel *
|
||||||
mg_backend_readmng_parse_page (MgBackendReadmng *self,
|
mg_backend_readmng_parse_page (MgBackendReadmng *self,
|
||||||
xmlDocPtr html_document);
|
xmlDocPtr html_document);
|
||||||
@ -235,7 +236,9 @@ mg_backend_readmng_fetch_page_url (MgBackendReadmng *self,
|
|||||||
GListStore *
|
GListStore *
|
||||||
mg_backend_readmng_search (MgBackendReadmng *self,
|
mg_backend_readmng_search (MgBackendReadmng *self,
|
||||||
const char *search_query) {
|
const char *search_query) {
|
||||||
char *response = mg_backend_readmng_fetch_search (self, search_query);
|
size_t response_len = 0;
|
||||||
|
char *response = mg_backend_readmng_fetch_search (self, search_query,
|
||||||
|
&response_len);
|
||||||
JsonParser *parser = json_parser_new ();
|
JsonParser *parser = json_parser_new ();
|
||||||
GListStore *mangas = g_list_store_new (MG_TYPE_MANGA);
|
GListStore *mangas = g_list_store_new (MG_TYPE_MANGA);
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
@ -243,7 +246,11 @@ mg_backend_readmng_search (MgBackendReadmng *self,
|
|||||||
JsonArray *mangas_json_array = NULL;
|
JsonArray *mangas_json_array = NULL;
|
||||||
guint mangas_json_array_len = 0;
|
guint mangas_json_array_len = 0;
|
||||||
|
|
||||||
json_parser_load_from_data (parser, response, -1, &error);
|
if (!response) {
|
||||||
|
g_warning ("Json search response is null.");
|
||||||
|
goto cleanup_mg_backend_readmng_search;
|
||||||
|
}
|
||||||
|
json_parser_load_from_data (parser, response, response_len, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
g_warning ("Unable to parse json: %s.", error->message);
|
g_warning ("Unable to parse json: %s.", error->message);
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
@ -256,7 +263,7 @@ mg_backend_readmng_search (MgBackendReadmng *self,
|
|||||||
mangas_json_array = json_node_get_array (root);
|
mangas_json_array = json_node_get_array (root);
|
||||||
mangas_json_array_len = json_array_get_length (
|
mangas_json_array_len = json_array_get_length (
|
||||||
mangas_json_array);
|
mangas_json_array);
|
||||||
for (guint i = 0; i < mangas_json_array_len; i++) {
|
for (guint i = 0; i < mangas_json_array_len && i < 19; i++) {
|
||||||
JsonObject *manga_json_object =
|
JsonObject *manga_json_object =
|
||||||
json_array_get_object_element (mangas_json_array, i);
|
json_array_get_object_element (mangas_json_array, i);
|
||||||
char *id_manga = NULL;
|
char *id_manga = NULL;
|
||||||
@ -280,14 +287,14 @@ cleanup_mg_backend_readmng_search:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
mg_backend_readmng_fetch_search (MgBackendReadmng *self, const char *search_query) {
|
mg_backend_readmng_fetch_search (MgBackendReadmng *self,
|
||||||
|
const char *search_query, size_t *response_len) {
|
||||||
MgUtilSoup *util_soup;
|
MgUtilSoup *util_soup;
|
||||||
MgUtilString *string_util;
|
MgUtilString *string_util;
|
||||||
|
|
||||||
char *request_url;
|
char *request_url;
|
||||||
|
|
||||||
size_t request_url_len;
|
size_t request_url_len;
|
||||||
size_t response_len = 0;
|
|
||||||
|
|
||||||
util_soup = mg_util_soup_new ();
|
util_soup = mg_util_soup_new ();
|
||||||
string_util = mg_util_string_new ();
|
string_util = mg_util_string_new ();
|
||||||
@ -328,7 +335,7 @@ mg_backend_readmng_fetch_search (MgBackendReadmng *self, const char *search_quer
|
|||||||
size_t body_len = sizeof body / sizeof *body;
|
size_t body_len = sizeof body / sizeof *body;
|
||||||
|
|
||||||
char *text_response = mg_util_soup_post_request_url_encoded (util_soup,
|
char *text_response = mg_util_soup_post_request_url_encoded (util_soup,
|
||||||
request_url, body, body_len, headers, headers_len, &response_len);
|
request_url, body, body_len, headers, headers_len, response_len);
|
||||||
|
|
||||||
g_free (request_url);
|
g_free (request_url);
|
||||||
g_free (phrase);
|
g_free (phrase);
|
||||||
@ -357,7 +364,7 @@ mg_backend_readmng_retrieve_manga_details (MgBackendReadmng *self,
|
|||||||
MgManga *manga) {
|
MgManga *manga) {
|
||||||
MgUtilXML *xml_utils;
|
MgUtilXML *xml_utils;
|
||||||
|
|
||||||
xmlDocPtr html_document;
|
xmlDocPtr html_document = NULL;
|
||||||
xmlNodePtr *movie_detail = NULL;
|
xmlNodePtr *movie_detail = NULL;
|
||||||
xmlXPathObjectPtr xpath_result = NULL;
|
xmlXPathObjectPtr xpath_result = NULL;
|
||||||
xmlNodeSetPtr node_set = NULL;
|
xmlNodeSetPtr node_set = NULL;
|
||||||
@ -402,6 +409,9 @@ cleanup_mg_backend_readmng_retrieve_manga_details:
|
|||||||
if (movie_detail) {
|
if (movie_detail) {
|
||||||
g_free (movie_detail);
|
g_free (movie_detail);
|
||||||
}
|
}
|
||||||
|
if (html_document) {
|
||||||
|
xmlFreeDoc(html_document);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GListStore *
|
static GListStore *
|
||||||
@ -446,6 +456,9 @@ cleanup_mg_backend_readmng_recover_chapter_list:
|
|||||||
xmlXPathFreeObject(xpath_result);
|
xmlXPathFreeObject(xpath_result);
|
||||||
}
|
}
|
||||||
if (uls) {
|
if (uls) {
|
||||||
|
for (size_t i = 0; i < ul_len; i++) {
|
||||||
|
xmlFreeNode(uls[i]);
|
||||||
|
}
|
||||||
g_free (uls);
|
g_free (uls);
|
||||||
}
|
}
|
||||||
return return_value;
|
return return_value;
|
||||||
@ -581,6 +594,7 @@ mg_backend_readmng_parse_main_page (MgBackendReadmng *self, const xmlDocPtr html
|
|||||||
xmlFreeNode (current_li);
|
xmlFreeNode (current_li);
|
||||||
li[i] = NULL;
|
li[i] = NULL;
|
||||||
}
|
}
|
||||||
|
xmlFreeNode(slides);
|
||||||
g_free (li);
|
g_free (li);
|
||||||
return mangas;
|
return mangas;
|
||||||
}
|
}
|
||||||
@ -636,6 +650,11 @@ cleanup_mg_backend_readmng_retrieve_slides:
|
|||||||
xmlXPathFreeObject(xpath_result);
|
xmlXPathFreeObject(xpath_result);
|
||||||
}
|
}
|
||||||
if (nodes) {
|
if (nodes) {
|
||||||
|
for (size_t i = 1; i < matching_classes_len; i++)
|
||||||
|
{
|
||||||
|
xmlFreeNode(nodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
g_free (nodes);
|
g_free (nodes);
|
||||||
}
|
}
|
||||||
return slides;
|
return slides;
|
||||||
|
@ -54,7 +54,6 @@ mg_util_soup_get_request (MgUtilSoup *self, const char *url, gsize *size_respons
|
|||||||
g_value_unset (&response);
|
g_value_unset (&response);
|
||||||
g_clear_object (&soup_session);
|
g_clear_object (&soup_session);
|
||||||
g_clear_object (&msg);
|
g_clear_object (&msg);
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +167,14 @@ set_image_zoomable_picture_container (ChapterVisorData *chapter_visor_data) {
|
|||||||
strlen(url_image_not_owned) + 1, 0,
|
strlen(url_image_not_owned) + 1, 0,
|
||||||
strlen (url_image_not_owned));
|
strlen (url_image_not_owned));
|
||||||
|
|
||||||
create_picture_from_url (url_image, 0, picture_ready_manga_page,
|
GtkPicture *picture = create_picture_from_url (url_image, 0, picture_ready_manga_page,
|
||||||
zoomable_picture_container, chapter_visor_data);
|
zoomable_picture_container, chapter_visor_data, false);
|
||||||
|
if (picture) {
|
||||||
|
chapter_visor_data->current_picture = GTK_PICTURE (picture);
|
||||||
|
g_signal_connect (G_OBJECT (picture), "map",
|
||||||
|
G_CALLBACK (image_page_show), chapter_visor_data);
|
||||||
|
gtk_scrolled_window_set_child (zoomable_picture_container, GTK_WIDGET (picture));
|
||||||
|
}
|
||||||
g_free (url_image);
|
g_free (url_image);
|
||||||
g_clear_object (&string_util);
|
g_clear_object (&string_util);
|
||||||
}
|
}
|
||||||
|
@ -89,8 +89,8 @@ create_detail_view (MgManga *manga, ControlsAdwaita *controls) {
|
|||||||
("network-transmit-receive-symbolic"));
|
("network-transmit-receive-symbolic"));
|
||||||
GtkListView *chapter_list = NULL;
|
GtkListView *chapter_list = NULL;
|
||||||
char *url_image = mg_manga_get_image_url(manga);
|
char *url_image = mg_manga_get_image_url(manga);
|
||||||
create_picture_from_url (url_image, 200,
|
GtkPicture *picture = create_picture_from_url (url_image, 200,
|
||||||
picture_ready_manga_detail, avatar_title_box, NULL);
|
picture_ready_manga_detail, avatar_title_box, NULL, false);
|
||||||
char *manga_title_text = mg_manga_get_title (manga);
|
char *manga_title_text = mg_manga_get_title (manga);
|
||||||
char *title_text = mg_util_xml_get_title_text (
|
char *title_text = mg_util_xml_get_title_text (
|
||||||
xml_util, manga_title_text);
|
xml_util, manga_title_text);
|
||||||
@ -116,6 +116,9 @@ create_detail_view (MgManga *manga, ControlsAdwaita *controls) {
|
|||||||
gtk_widget_set_size_request (GTK_WIDGET (manga_description), 200, -1);
|
gtk_widget_set_size_request (GTK_WIDGET (manga_description), 200, -1);
|
||||||
|
|
||||||
gtk_label_set_use_markup (GTK_LABEL (manga_title), 1);
|
gtk_label_set_use_markup (GTK_LABEL (manga_title), 1);
|
||||||
|
if (picture) {
|
||||||
|
gtk_box_append (avatar_title_box, GTK_WIDGET (picture));
|
||||||
|
}
|
||||||
gtk_box_append (avatar_title_box, GTK_WIDGET (manga_title));
|
gtk_box_append (avatar_title_box, GTK_WIDGET (manga_title));
|
||||||
|
|
||||||
gtk_box_append (foldable_manga_data, GTK_WIDGET (avatar_title_box));
|
gtk_box_append (foldable_manga_data, GTK_WIDGET (avatar_title_box));
|
||||||
|
@ -26,6 +26,15 @@ manga_selected (GtkListView *list_view,
|
|||||||
guint position,
|
guint position,
|
||||||
gpointer user_data) {
|
gpointer user_data) {
|
||||||
ControlsAdwaita *controls = (ControlsAdwaita *) user_data;
|
ControlsAdwaita *controls = (ControlsAdwaita *) user_data;
|
||||||
|
controls->avoid_list_image_downloads = true;;
|
||||||
|
for (size_t i = 0; i < controls->image_threads_len; i++) {
|
||||||
|
g_cancellable_cancel (controls->image_threads[i]);
|
||||||
|
}
|
||||||
|
if (controls->image_threads) {
|
||||||
|
g_free (controls->image_threads);
|
||||||
|
}
|
||||||
|
controls->image_threads = NULL;
|
||||||
|
controls->image_threads_len = 0;
|
||||||
AdwLeaflet *views_leaflet = controls->views_leaflet;
|
AdwLeaflet *views_leaflet = controls->views_leaflet;
|
||||||
GtkSingleSelection *selection = GTK_SINGLE_SELECTION
|
GtkSingleSelection *selection = GTK_SINGLE_SELECTION
|
||||||
(gtk_list_view_get_model (list_view));
|
(gtk_list_view_get_model (list_view));
|
||||||
@ -44,8 +53,10 @@ manga_selected (GtkListView *list_view,
|
|||||||
GtkBox *detail_view = create_detail_view (manga, controls);
|
GtkBox *detail_view = create_detail_view (manga, controls);
|
||||||
adw_leaflet_append (views_leaflet, GTK_WIDGET (detail_view));
|
adw_leaflet_append (views_leaflet, GTK_WIDGET (detail_view));
|
||||||
adw_leaflet_navigate (views_leaflet, ADW_NAVIGATION_DIRECTION_FORWARD);
|
adw_leaflet_navigate (views_leaflet, ADW_NAVIGATION_DIRECTION_FORWARD);
|
||||||
|
controls->avoid_list_image_downloads = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LIST_IMAGES
|
||||||
static void
|
static void
|
||||||
picture_ready_manga_preview (GObject *source_object,
|
picture_ready_manga_preview (GObject *source_object,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
@ -58,21 +69,37 @@ picture_ready_manga_preview (GObject *source_object,
|
|||||||
gtk_box_prepend (box, picture);
|
gtk_box_prepend (box, picture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
setup_list_view_mangas (GtkSignalListItemFactory *factory,
|
setup_list_view_mangas (GtkSignalListItemFactory *factory,
|
||||||
GtkListItem *list_item,
|
GtkListItem *list_item,
|
||||||
gpointer user_data) {
|
gpointer user_data) {
|
||||||
|
ControlsAdwaita *controls = (ControlsAdwaita *) user_data;
|
||||||
MgManga *manga = gtk_list_item_get_item (list_item);
|
MgManga *manga = gtk_list_item_get_item (list_item);
|
||||||
GtkBox *box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
|
GtkBox *box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
|
||||||
char *manga_title = mg_manga_get_title (manga);
|
char *manga_title = mg_manga_get_title (manga);
|
||||||
char *image_url = mg_manga_get_image_url (manga);
|
char *image_url = mg_manga_get_image_url (manga);
|
||||||
|
|
||||||
GtkWidget *label = gtk_label_new (manga_title);
|
GtkWidget *label = gtk_label_new (manga_title);
|
||||||
create_picture_from_url (image_url, 100,
|
GtkPicture *picture = NULL;
|
||||||
picture_ready_manga_preview, box, NULL);
|
#ifdef LIST_IMAGES
|
||||||
|
GCancellable *cancellable = g_cancellable_new ();
|
||||||
|
picture = create_picture_from_url (image_url, 100,
|
||||||
|
picture_ready_manga_preview, box, cancellable,
|
||||||
|
controls->avoid_list_image_downloads);
|
||||||
|
controls->image_threads_len++;
|
||||||
|
controls->image_threads = g_realloc (controls->image_threads,
|
||||||
|
controls->image_threads_len * sizeof *(controls->image_threads));
|
||||||
|
controls->image_threads[controls->image_threads_len-1] = cancellable;
|
||||||
|
#endif
|
||||||
|
|
||||||
g_object_set_property_int (G_OBJECT(box), "height-request", 100);
|
g_object_set_property_int (G_OBJECT(box), "height-request", 100);
|
||||||
|
#ifdef LIST_IMAGES
|
||||||
|
if (picture) {
|
||||||
|
gtk_box_append (box, GTK_WIDGET (picture));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
gtk_box_append (box, label);
|
gtk_box_append (box, label);
|
||||||
|
|
||||||
gtk_list_item_set_child (list_item, GTK_WIDGET (box));
|
gtk_list_item_set_child (list_item, GTK_WIDGET (box));
|
||||||
@ -82,14 +109,13 @@ setup_list_view_mangas (GtkSignalListItemFactory *factory,
|
|||||||
|
|
||||||
GtkListView *
|
GtkListView *
|
||||||
create_list_view_mangas (GListStore *mangas, ControlsAdwaita *controls) {
|
create_list_view_mangas (GListStore *mangas, ControlsAdwaita *controls) {
|
||||||
AdwLeaflet *views_leaflet = controls->views_leaflet;
|
|
||||||
GtkSingleSelection *selection = gtk_single_selection_new (G_LIST_MODEL (mangas));
|
GtkSingleSelection *selection = gtk_single_selection_new (G_LIST_MODEL (mangas));
|
||||||
GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
|
GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
|
||||||
GtkListView *list_view_manga = NULL;
|
GtkListView *list_view_manga = NULL;
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (factory), "bind",
|
g_signal_connect (G_OBJECT (factory), "bind",
|
||||||
G_CALLBACK (setup_list_view_mangas),
|
G_CALLBACK (setup_list_view_mangas),
|
||||||
views_leaflet);
|
controls);
|
||||||
|
|
||||||
list_view_manga = GTK_LIST_VIEW (gtk_list_view_new (GTK_SELECTION_MODEL (selection),
|
list_view_manga = GTK_LIST_VIEW (gtk_list_view_new (GTK_SELECTION_MODEL (selection),
|
||||||
factory));
|
factory));
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
#ifndef _WIN32
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <adwaita.h>
|
#include <adwaita.h>
|
||||||
@ -37,6 +39,7 @@ activate (AdwApplication *app,
|
|||||||
AdwLeaflet *views_leaflet_search;
|
AdwLeaflet *views_leaflet_search;
|
||||||
AdwHeaderBar *header_bar;
|
AdwHeaderBar *header_bar;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
swipe_back_t swipe_back = (swipe_back_t) dlsym
|
swipe_back_t swipe_back = (swipe_back_t) dlsym
|
||||||
(NULL, "adw_leaflet_set_can_navigate_back");
|
(NULL, "adw_leaflet_set_can_navigate_back");
|
||||||
|
|
||||||
@ -44,11 +47,16 @@ activate (AdwApplication *app,
|
|||||||
swipe_back = (swipe_back_t) dlsym
|
swipe_back = (swipe_back_t) dlsym
|
||||||
(NULL, "adw_leaflet_set_can_swipe_back");
|
(NULL, "adw_leaflet_set_can_swipe_back");
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
swipe_back_t swipe_back = adw_leaflet_set_can_navigate_back;
|
||||||
|
#endif
|
||||||
|
|
||||||
controls->is_set_previous = 0;
|
controls->is_set_previous = 0;
|
||||||
controls->header = NULL;
|
controls->header = NULL;
|
||||||
controls->view_stack = view_stack;
|
controls->view_stack = view_stack;
|
||||||
|
controls->image_threads_len = 0;
|
||||||
|
controls->image_threads = NULL;
|
||||||
|
controls->avoid_list_image_downloads = false;
|
||||||
|
|
||||||
views_leaflet_explore = create_explore_leaflet (controls, swipe_back);
|
views_leaflet_explore = create_explore_leaflet (controls, swipe_back);
|
||||||
views_leaflet_search = create_search_leaflet (controls, swipe_back);
|
views_leaflet_search = create_search_leaflet (controls, swipe_back);
|
||||||
|
@ -16,6 +16,7 @@ const char *const IMAGE_CACHE_FORMAT_STRING =
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
char *url;
|
char *url;
|
||||||
gint picture_size;
|
gint picture_size;
|
||||||
|
GFile *image;
|
||||||
} PictureThreadAttributes;
|
} PictureThreadAttributes;
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@ -30,7 +31,7 @@ threaded_picture_recover (GTask *task, gpointer source_object,
|
|||||||
const char *url = attrs->url;
|
const char *url = attrs->url;
|
||||||
gint picture_size = attrs->picture_size;
|
gint picture_size = attrs->picture_size;
|
||||||
GFileIOStream *iostream = NULL;
|
GFileIOStream *iostream = NULL;
|
||||||
GFile *image = NULL;
|
GFile *image = attrs->image;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GdkTexture *texture = NULL;
|
GdkTexture *texture = NULL;
|
||||||
GtkPicture *picture = NULL;
|
GtkPicture *picture = NULL;
|
||||||
@ -39,15 +40,12 @@ threaded_picture_recover (GTask *task, gpointer source_object,
|
|||||||
char *downloaded_image = NULL;
|
char *downloaded_image = NULL;
|
||||||
|
|
||||||
MgUtilSoup *util_soup = mg_util_soup_new ();
|
MgUtilSoup *util_soup = mg_util_soup_new ();
|
||||||
|
downloaded_image = mg_util_soup_get_request (util_soup,
|
||||||
|
url, &size_downloaded_image);
|
||||||
static GMutex mutex;
|
static GMutex mutex;
|
||||||
g_mutex_lock (&mutex);
|
g_mutex_lock (&mutex);
|
||||||
image = get_image_for_url (url);
|
|
||||||
g_mutex_unlock (&mutex);
|
|
||||||
if (!g_file_query_exists (image, NULL)) {
|
if (!g_file_query_exists (image, NULL)) {
|
||||||
downloaded_image =
|
g_info ("Storing %s", url);
|
||||||
mg_util_soup_get_request
|
|
||||||
(util_soup,
|
|
||||||
url, &size_downloaded_image);
|
|
||||||
iostream = g_file_create_readwrite (image, G_FILE_CREATE_NONE,
|
iostream = g_file_create_readwrite (image, G_FILE_CREATE_NONE,
|
||||||
NULL, &error);
|
NULL, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -63,9 +61,11 @@ threaded_picture_recover (GTask *task, gpointer source_object,
|
|||||||
goto cleanup_create_picture_from_url;
|
goto cleanup_create_picture_from_url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
g_mutex_unlock (&mutex);
|
||||||
texture = gdk_texture_new_from_file (image, &error);
|
texture = gdk_texture_new_from_file (image, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
fprintf (stderr, "Texture malformed.");
|
g_warning ("Texture malformed.");
|
||||||
|
g_clear_error (&error);
|
||||||
goto cleanup_create_picture_from_url;
|
goto cleanup_create_picture_from_url;
|
||||||
}
|
}
|
||||||
picture = GTK_PICTURE (gtk_picture_new_for_paintable (GDK_PAINTABLE (texture)));
|
picture = GTK_PICTURE (gtk_picture_new_for_paintable (GDK_PAINTABLE (texture)));
|
||||||
@ -93,21 +93,44 @@ free_picture_thread_attributes (gpointer user_data) {
|
|||||||
g_free (attrs);
|
g_free (attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
GtkPicture *
|
||||||
create_picture_from_url (const char *const url, gint picture_size,
|
create_picture_from_url (const char *const url, gint picture_size,
|
||||||
GAsyncReadyCallback ready, gpointer source_object,
|
GAsyncReadyCallback ready, gpointer source_object,
|
||||||
gpointer callback_data) {
|
gpointer callback_data, bool do_not_download) {
|
||||||
GTask *task = g_task_new (source_object, NULL, ready, callback_data);
|
GtkPicture *picture = NULL;
|
||||||
|
GFile *image = NULL;
|
||||||
|
GdkTexture *texture = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
image = get_image_for_url (url);
|
||||||
size_t url_len = strlen (url) + 1;
|
size_t url_len = strlen (url) + 1;
|
||||||
|
|
||||||
PictureThreadAttributes *attrs = g_malloc (sizeof *attrs);
|
if (g_file_query_exists (image, NULL)) {
|
||||||
|
texture = gdk_texture_new_from_file (image, &error);
|
||||||
|
if (error) {
|
||||||
|
g_warning ("Texture malformed.");
|
||||||
|
g_clear_error (&error);
|
||||||
|
goto cleanup_create_picture_from_url;
|
||||||
|
}
|
||||||
|
picture = GTK_PICTURE (gtk_picture_new_for_paintable (GDK_PAINTABLE (texture)));
|
||||||
|
if (GTK_IS_WIDGET (picture)) {
|
||||||
|
g_object_set_property_int (G_OBJECT(picture), "height-request", picture_size);
|
||||||
|
g_object_set_property_int (G_OBJECT(picture), "width-request", picture_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (!do_not_download) {
|
||||||
|
GTask *task = g_task_new (source_object, NULL, ready, callback_data);
|
||||||
|
PictureThreadAttributes *attrs = g_malloc (sizeof *attrs);
|
||||||
attrs->url = g_malloc (url_len * sizeof *url);
|
attrs->url = g_malloc (url_len * sizeof *url);
|
||||||
snprintf (attrs->url, url_len, "%s", url);
|
snprintf (attrs->url, url_len, "%s", url);
|
||||||
|
attrs->image = image;
|
||||||
attrs->picture_size = picture_size;
|
attrs->picture_size = picture_size;
|
||||||
g_task_set_task_data (task, attrs, free_picture_thread_attributes);
|
g_task_set_task_data (task, attrs, free_picture_thread_attributes);
|
||||||
|
g_task_set_return_on_cancel (task, true);
|
||||||
g_task_run_in_thread (task, threaded_picture_recover);
|
g_task_run_in_thread (task, threaded_picture_recover);
|
||||||
|
}
|
||||||
|
cleanup_create_picture_from_url:
|
||||||
|
return picture;
|
||||||
}
|
}
|
||||||
|
|
||||||
GFile *
|
GFile *
|
||||||
|
@ -6,18 +6,14 @@
|
|||||||
#include <openmg/view/list_view_manga.h>
|
#include <openmg/view/list_view_manga.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
search_text_changed (GtkEditable *self,
|
search_text_changed (GtkEntry *entry,
|
||||||
gpointer user_data);
|
|
||||||
static void
|
|
||||||
async_search_manga (GTask *task,
|
|
||||||
gpointer source_object,
|
|
||||||
gpointer task_data,
|
|
||||||
GCancellable *cancellable);
|
|
||||||
static void
|
|
||||||
set_mangas_to_list_view (GObject *source_object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GtkListView *list_view_mangas;
|
||||||
|
ControlsAdwaita *controls;
|
||||||
|
} SearchTextData;
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
create_search_view (ControlsAdwaita *controls) {
|
create_search_view (ControlsAdwaita *controls) {
|
||||||
GtkWidget *search_view = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
GtkWidget *search_view = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
||||||
@ -26,12 +22,15 @@ create_search_view (ControlsAdwaita *controls) {
|
|||||||
GtkWidget *scroll = gtk_scrolled_window_new ();
|
GtkWidget *scroll = gtk_scrolled_window_new ();
|
||||||
GListStore *mangas = g_list_store_new(MG_TYPE_MANGA);
|
GListStore *mangas = g_list_store_new(MG_TYPE_MANGA);
|
||||||
GtkListView *list_view_mangas;
|
GtkListView *list_view_mangas;
|
||||||
|
SearchTextData *search_text_data = g_malloc (sizeof *search_text_data);
|
||||||
|
|
||||||
gtk_box_append (GTK_BOX (search_view), search_entry);
|
gtk_box_append (GTK_BOX (search_view), search_entry);
|
||||||
|
|
||||||
list_view_mangas = create_list_view_mangas (mangas, controls);
|
list_view_mangas = create_list_view_mangas (mangas, controls);
|
||||||
g_signal_connect (search_entry, "changed",
|
search_text_data->list_view_mangas = list_view_mangas;
|
||||||
G_CALLBACK (search_text_changed), list_view_mangas);
|
search_text_data ->controls = controls;
|
||||||
|
g_signal_connect (search_entry, "activate",
|
||||||
|
G_CALLBACK (search_text_changed), search_text_data);
|
||||||
|
|
||||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scroll),
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scroll),
|
||||||
GTK_WIDGET (list_view_mangas));
|
GTK_WIDGET (list_view_mangas));
|
||||||
@ -42,43 +41,29 @@ create_search_view (ControlsAdwaita *controls) {
|
|||||||
return search_view;
|
return search_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GCancellable *cancellable = NULL;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
search_text_changed (GtkEditable *editable,
|
search_text_changed (GtkEntry *entry,
|
||||||
gpointer user_data) {
|
gpointer user_data) {
|
||||||
if (cancellable) {
|
SearchTextData *search_text_data = (SearchTextData *) user_data;
|
||||||
g_cancellable_cancel (cancellable);
|
ControlsAdwaita *controls = search_text_data->controls;
|
||||||
}
|
GtkListView *list_view_mangas = search_text_data->list_view_mangas;
|
||||||
cancellable = g_cancellable_new ();
|
|
||||||
GtkListView *list_view_mangas = GTK_LIST_VIEW (user_data);
|
|
||||||
GTask *task = g_task_new (editable, cancellable, set_mangas_to_list_view,list_view_mangas);
|
|
||||||
g_task_set_return_on_cancel (task, true);
|
|
||||||
g_task_run_in_thread (task, async_search_manga);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_mangas_to_list_view (GObject *source_object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data) {
|
|
||||||
GListStore *mangas = G_LIST_STORE (g_task_propagate_pointer (G_TASK (res), NULL));
|
|
||||||
if (!mangas) return;
|
|
||||||
GtkListView *list_view_mangas = GTK_LIST_VIEW (user_data);
|
|
||||||
GtkSingleSelection *selection = GTK_SINGLE_SELECTION (
|
|
||||||
gtk_list_view_get_model (list_view_mangas));
|
|
||||||
gtk_single_selection_set_model (selection,
|
|
||||||
G_LIST_MODEL (mangas));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
async_search_manga (GTask *task,
|
|
||||||
gpointer source_object,
|
|
||||||
gpointer task_data,
|
|
||||||
GCancellable *cancellable) {
|
|
||||||
GtkEntry *entry = GTK_ENTRY (source_object);
|
|
||||||
GtkEntryBuffer *buffer = gtk_entry_get_buffer (entry);
|
GtkEntryBuffer *buffer = gtk_entry_get_buffer (entry);
|
||||||
MgBackendReadmng *readmng = mg_backend_readmng_new ();
|
MgBackendReadmng *readmng = mg_backend_readmng_new ();
|
||||||
const char *search_string = gtk_entry_buffer_get_text (buffer);
|
const char *search_string = gtk_entry_buffer_get_text (buffer);
|
||||||
GListStore *mangas = mg_backend_readmng_search (readmng, search_string);
|
GListStore *mangas = mg_backend_readmng_search (readmng, search_string);
|
||||||
g_task_return_pointer (task, mangas, g_object_unref);
|
for (size_t i = 0; i < controls->image_threads_len; i++) {
|
||||||
|
g_cancellable_cancel (controls->image_threads[i]);
|
||||||
|
}
|
||||||
|
if (controls->image_threads) {
|
||||||
|
g_free (controls->image_threads);
|
||||||
|
}
|
||||||
|
controls->image_threads = NULL;
|
||||||
|
controls->image_threads_len = 0;
|
||||||
|
controls->avoid_list_image_downloads = true;
|
||||||
|
if (!mangas) return;
|
||||||
|
GtkSingleSelection *selection = GTK_SINGLE_SELECTION (
|
||||||
|
gtk_list_view_get_model (list_view_mangas));
|
||||||
|
controls->avoid_list_image_downloads = false;
|
||||||
|
gtk_single_selection_set_model (selection,
|
||||||
|
G_LIST_MODEL (mangas));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user