From cc727e972f7fdc871ee1f42cf014151b67422bf0 Mon Sep 17 00:00:00 2001 From: nirav Date: Tue, 26 Mar 2019 07:54:56 +0530 Subject: Update login flow and timeline window --- .gitignore | 1 + Makefile | 69 ++++++++------ data/avi.png | Bin 0 -> 997 bytes data/login_window.ui | 178 ++++++++++++++++++++++++++++++++++++ data/post.ui | 245 ++++++++++++++++++++++++++++---------------------- src/account.c | 92 +++++++++++++++++++ src/account.h | 4 +- src/config.c | 16 +--- src/http.c | 2 - src/login_window.c | 117 ++++++++++-------------- src/login_window.h | 2 +- src/main.c | 12 +-- src/main_window.c | 167 ++++++++++++++++++++++++++++++++++ src/main_window.h | 9 ++ src/status.c | 8 ++ src/timeline.c | 1 - src/timeline_window.c | 120 ------------------------- src/timeline_window.h | 9 -- 18 files changed, 693 insertions(+), 359 deletions(-) create mode 100644 data/avi.png create mode 100644 data/login_window.ui create mode 100644 src/account.c create mode 100644 src/main_window.c create mode 100644 src/main_window.h delete mode 100644 src/timeline_window.c delete mode 100644 src/timeline_window.h diff --git a/.gitignore b/.gitignore index e7d5256..50fcf1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +*~ *.o ap_client diff --git a/Makefile b/Makefile index 0134d5e..781f0aa 100644 --- a/Makefile +++ b/Makefile @@ -1,36 +1,34 @@ -CC=cc -PKGCONFIG=$(shell which pkg-config) - -CFLAGS=-o2 -pipe -CFLAGS+=-Wall -Wextra -Wno-unused-parameter -std=c99 -CFLAGS+=$(shell $(PKGCONFIG) --cflags gtk+-3.0 libcurl jansson) -lpthread -LDFLAGS+=$(shell $(PKGCONFIG) --libs gtk+-3.0 libcurl jansson) -lpthread +.POSIX: +CC=c99 +CFLAGS=-Wall -Wextra -Wno-unused-parameter +E_CGLAGS=$$(pkg-config --cflags gtk+-3.0 jansson libcurl) $(CFLAGS) +LDFLAGS= +E_LDFLAGS=$$(pkg-config --libs gtk+-3.0 jansson libcurl) $(LDFLAGS) DESTDIR= PREFIX=/usr/local BINDIR=$(PREFIX)/bin -OUTDIR=build -OBJECTS=$(OUTDIR)/main.o \ - $(OUTDIR)/string-util.o \ - $(OUTDIR)/instance_info.o \ - $(OUTDIR)/http.o \ - $(OUTDIR)/status.o \ - $(OUTDIR)/timeline.o \ - $(OUTDIR)/auth.o \ - $(OUTDIR)/register.o \ - $(OUTDIR)/login_window.o \ - $(OUTDIR)/timeline_window.o \ - $(OUTDIR)/config.o \ - $(OUTDIR)/log.o +OBJECTS=src/main.o \ + src/string-util.o \ + src/instance_info.o \ + src/http.o \ + src/status.o \ + src/account.o \ + src/timeline.o \ + src/auth.o \ + src/register.o \ + src/login_window.o \ + src/main_window.o \ + src/config.o \ + src/log.o all: ap_client ap_client: $(OBJECTS) - $(CC) $(LDFLAGS) -o ap_client $(OBJECTS) + $(CC) $(E_LDFLAGS) -o ap_client $(OBJECTS) -$(OUTDIR)/%.o: src/%.c src/*.h - @mkdir -p $(OUTDIR) - $(CC) $(CFLAGS) -c -o $@ $< +.c.o: + $(CC) $(E_CGLAGS) -c -o $@ $< install: ap_client mkdir -p $(DESTDIR)$(BINDIR) @@ -39,9 +37,28 @@ install: ap_client clean: rm -f ap_client - rm -rf $(OUTDIR) + rm -rf src/*.o uninstall: rm -f $(DESTDIR)$(BINDIR)/ap_client -.PHONY: all clean install uninstall +src/account.o: src/account.c src/account.h src/log.h +src/auth.o: src/auth.c src/string-util.h src/auth.h src/http.h \ + src/config.h src/log.h +src/config.o: src/config.c src/string-util.h src/config.h src/log.h +src/http.o: src/http.c src/string-util.h src/auth.h src/config.h \ + src/log.h +src/instance_info.o: src/instance_info.c src/instance_info.h src/log.h +src/log.o: src/log.c src/log.h +src/login_window.o: src/login_window.c src/auth.h src/register.h \ + src/http.h src/timeline.h src/status.h src/account.h src/main_window.h \ + src/log.h +src/main.o: src/main.c src/http.h src/config.h src/main_window.h +src/main_window.o: src/main_window.c src/auth.h src/http.h src/timeline.h \ + src/status.h src/account.h src/log.h src/config.h src/login_window.h \ + src/string-util.h +src/register.o: src/register.c src/http.h src/config.h src/log.h +src/status.o: src/status.c src/status.h src/account.h src/log.h +src/string-util.o: src/string-util.c +src/timeline.o: src/timeline.c src/timeline.h src/status.h src/account.h \ + src/auth.h src/config.h src/http.h src/string-util.h src/log.h diff --git a/data/avi.png b/data/avi.png new file mode 100644 index 0000000..3fc699c Binary files /dev/null and b/data/avi.png differ diff --git a/data/login_window.ui b/data/login_window.ui new file mode 100644 index 0000000..9f409ff --- /dev/null +++ b/data/login_window.ui @@ -0,0 +1,178 @@ + + + + + + 500 + 400 + False + dialog + + + False + vertical + 2 + + + False + end + + + Login + True + False + True + True + + + + True + True + 0 + + + + + Cancel + True + True + True + + + True + True + 1 + + + + + False + False + end + 0 + + + + + 250 + True + False + center + center + 4 + 4 + 4 + 4 + True + True + vertical + 4 + + + True + False + start + Instance Domain + + + False + True + 0 + + + + + True + True + applications-internet + Instance Domain + example.com + + + False + True + 1 + + + + + True + False + start + Email + + + False + True + 2 + + + + + True + True + mail-mark-read + username@example.com + email + + + False + True + 3 + + + + + True + False + start + Password + + + False + True + 4 + + + + + True + True + False + + help-about + 1234 + password + + + False + True + 5 + + + + + True + False + + + False + True + 4 + 6 + + + + + False + True + 1 + + + + + + + + + diff --git a/data/post.ui b/data/post.ui index da222d8..47f23ae 100644 --- a/data/post.ui +++ b/data/post.ui @@ -25,100 +25,49 @@ along with . If not, see . True False - 4 - 4 - 4 - 4 - 8 - top - - - True - False - start - gtk-select-color - 6 - - - False - False - 0 - - + vertical + 10 True False - start - vertical + 4 + 4 8 + top - + True False - - - True - False - Display Name - - - False - True - 0 - - - - - True - False - @username - - - False - True - 1 - - + start + avi.png + 6 False - True + False 0 - - - True - False - A widget’s index in the overlay children list determines which order the children are drawn if they overlap. The first child is drawn at the bottom. It also affects the default focus chain order. - True - True - char - - - False - True - 1 - - True False - 20 + start + vertical + 8 True False - start - 10 - 5 - + True False - mail-reply-sender + Display Name + + + False @@ -130,7 +79,8 @@ along with . If not, see . True False - 4 + 4 + @ False @@ -138,6 +88,18 @@ along with . If not, see . 1 + + + True + False + username + + + False + True + 2 + + False @@ -146,36 +108,13 @@ along with . If not, see . - + True False - start - 10 - 5 - - - True - False - media-playlist-repeat - - - False - True - 0 - - - - - True - False - 4 - - - False - True - 1 - - + A widget’s index in the overlay children list determines which order the children are drawn if they overlap. The first child is drawn at the bottom. It also affects the default focus chain order. + True + True + char False @@ -187,13 +126,37 @@ along with . If not, see . True False - 10 - 5 + 20 - + True False - emblem-favorite + start + 5 + + + True + False + mail-reply-sender + + + False + True + 0 + + + + + True + False + 0 + + + False + True + 1 + + False @@ -202,10 +165,35 @@ along with . If not, see . - + True False - 4 + start + 5 + + + True + False + media-playlist-repeat + + + False + True + 0 + + + + + True + False + 0 + + + False + True + 1 + + False @@ -213,6 +201,42 @@ along with . If not, see . 1 + + + True + False + 5 + + + True + False + help-about + + + False + True + 0 + + + + + True + False + 0 + + + False + True + 1 + + + + + False + True + 2 + + False @@ -224,10 +248,21 @@ along with . If not, see . False True - 2 + 1 + + False + True + 0 + + + + + True + False + False True diff --git a/src/account.c b/src/account.c new file mode 100644 index 0000000..c407d56 --- /dev/null +++ b/src/account.c @@ -0,0 +1,92 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include "account.h" +#include "log.h" + +struct account *account_from_json(const char *json_data) +{ + struct account *a; + json_t *root; + json_error_t error; + + root = json_loads(json_data, 0, &error); + if (!root) { + log_msg(LOG_WARNING, "account_from_json", "json parse error: line %d: %s", + error.line, error.text); + return NULL; + } + + a = account_from_json_t(root); + json_decref(root); + return a; +} + +struct account *account_from_json_t(const json_t *root) +{ + struct account *a; + if (!root) { + log_msg(LOG_WARNING, "account_from_json_t", "json data is null"); + return NULL; + } + + if (!json_is_object(root)) { + log_msg(LOG_WARNING, "account_from_json_t", "json root is not object"); + return NULL; + } + + a = calloc(1, sizeof(struct account)); + if (!a) { + err(1, "account_from_json_t"); + return NULL; + } + + json_t *id = json_object_get(root, "id"); + if (json_is_string(id)) { + a->id = strdup(json_string_value(id)); + } + + json_t *username = json_object_get(root, "username"); + if (json_is_string(username)) { + a->username = strdup(json_string_value(username)); + } + + json_t *acct = json_object_get(root, "acct"); + if (json_is_string(acct)) { + a->acct = strdup(json_string_value(acct)); + } + + json_t *display_name = json_object_get(root, "display_name"); + if (json_is_string(display_name)) { + a->display_name = strdup(json_string_value(display_name)); + } + + return a; +} + +void account_free(struct account *a) +{ + if (a->id) + free(a->id); + if (a->username) + free(a->username); + if (a->acct) + free(a->acct); + if (a->display_name) + free(a->display_name); + if (a->note) + free(a->note); + if (a->url) + free(a->url); + if (a->avatar) + free(a->avatar); + if (a->avatar_static) + free(a->avatar_static); + if (a->header) + free(a->header); + if (a->header_static) + free(a->header_static); + free(a); +} + diff --git a/src/account.h b/src/account.h index 049c829..547f276 100644 --- a/src/account.h +++ b/src/account.h @@ -22,6 +22,8 @@ struct account { bool bot; }; -struct account *account_from_json(char *json_data); +struct account *account_from_json(const char *json_data); +struct account *account_from_json_t(const json_t *); +void account_free(struct account *); #endif diff --git a/src/config.c b/src/config.c index 211e953..f409700 100644 --- a/src/config.c +++ b/src/config.c @@ -18,22 +18,13 @@ struct config _config; const struct config *config = (const struct config *)&_config; -int read_local_credentials() +bool is_logged_in() { if (!(config->access_token) || !*(config->access_token) || !(config->instance_url) || !*(config->instance_url)) { - log_msg(LOG_WARNING, "read_local_credentials", - "access_token not found"); - return -1; + return false; } - return 0; -} - -bool is_logged_in() -{ - if (config->access_token) - return true; - return false; + return true; } const char *get_access_token() @@ -162,7 +153,6 @@ void config_set_client_secret(const char *cs) void config_set_instance_url(const char *iu) { - printf("updating url: %s", iu); _config.instance_url = strdup(iu); } diff --git a/src/http.c b/src/http.c index 84b62be..ddd0470 100644 --- a/src/http.c +++ b/src/http.c @@ -65,8 +65,6 @@ char *get_request(const char *url) struct write_result write_result = {.data = data, .pos = 0}; - log_msg(LOG_INFO, "get_request", "loggedid: %d, token: %s", is_logged_in(), get_access_token()); - if (is_logged_in()) { const char *token = get_access_token(); size_t s = strlen(AUTH_HEADER_STR_PREFIX) + strlen(token) + 1; diff --git a/src/login_window.c b/src/login_window.c index a060d6c..241ca9b 100644 --- a/src/login_window.c +++ b/src/login_window.c @@ -8,32 +8,28 @@ #include "register.h" #include "http.h" #include "timeline.h" -#include "timeline_window.h" +#include "main_window.h" #include "log.h" GtkApplication *application; -static GtkWidget *window; -static GtkWidget *box; -static GtkWidget *instance_name_box, *email_box, *password_box; -static GtkWidget *submit_button; -static GtkWidget *spinner; +GObject *login_dialog; +GObject *instance_domain_entry, *email_entry, *password_entry; +GObject *login_button, *cancel_button; +GObject *spinner; static gboolean login_completed(gpointer data) { int *val_ptr = data; gtk_spinner_stop(GTK_SPINNER(spinner)); if (*val_ptr) { + free(val_ptr); log_msg(LOG_WARNING, "login_callback", "login failed"); + return G_SOURCE_REMOVE; } else { - create_timeline_window(application, NULL); + free(val_ptr); + gtk_widget_destroy(GTK_WIDGET(login_dialog)); + return G_SOURCE_REMOVE; } - - /* gtk_window_close(GTK_WINDOW(window)); */ - /* gtk_application_remove_window( */ - /* GTK_APPLICATION(application), GTK_WINDOW(window)); */ - - free(val_ptr); - return G_SOURCE_REMOVE; } static gpointer user_register(gpointer data) @@ -41,9 +37,9 @@ static gpointer user_register(gpointer data) int *val_ptr; const char *instance_name, *email, *password; - instance_name = gtk_entry_get_text(GTK_ENTRY(instance_name_box)); - email = gtk_entry_get_text(GTK_ENTRY(email_box)); - password = gtk_entry_get_text(GTK_ENTRY(password_box)); + instance_name = gtk_entry_get_text(GTK_ENTRY(instance_domain_entry)); + email = gtk_entry_get_text(GTK_ENTRY(email_entry)); + password = gtk_entry_get_text(GTK_ENTRY(password_entry)); val_ptr = malloc(sizeof(int)); *val_ptr = register_app(instance_name); @@ -68,15 +64,16 @@ static void submit_login_form() static bool is_form_valid() { - if (strlen(gtk_entry_get_text(GTK_ENTRY(instance_name_box))) < 1 || - strlen(gtk_entry_get_text(GTK_ENTRY(email_box))) < 1 || - strlen(gtk_entry_get_text(GTK_ENTRY(password_box))) < 1) + if (strlen(gtk_entry_get_text(GTK_ENTRY(instance_domain_entry))) < 1 || + strlen(gtk_entry_get_text(GTK_ENTRY(email_entry))) < 1 || + strlen(gtk_entry_get_text(GTK_ENTRY(password_entry))) < 1) return false; return true; } -static void submit_button_clicked(GtkButton *button, gpointer user_data) +static void login_button_click(GtkButton *button, gpointer user_data) { + g_print("clicked\n"); if (is_form_valid()) submit_login_form(); } @@ -87,67 +84,45 @@ static void form_on_activate(GtkEntry *entry, gpointer user_data) submit_login_form(); } -static void on_form_changed(GtkWidget *widget, gpointer data) +static void login_form_changed(GtkWidget *widget, gpointer data) { if (is_form_valid()) - gtk_widget_set_sensitive(GTK_WIDGET(submit_button), true); + gtk_widget_set_sensitive(GTK_WIDGET(login_button), true); else - gtk_widget_set_sensitive(GTK_WIDGET(submit_button), false); + gtk_widget_set_sensitive(GTK_WIDGET(login_button), false); } -void create_login_window(GtkApplication *app, gpointer user_data) +int create_login_dialog() { - application = app; - window = gtk_application_window_new(app); - gtk_window_set_title(GTK_WINDOW(window), "ap_client"); - gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); - gtk_container_set_border_width(GTK_CONTAINER(window), 10); - /* g_signal_connect(app, "window-removed", G_CALLBACK(window_removed), NULL); */ - - box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); - gtk_widget_set_valign(GTK_WIDGET(box), GTK_ALIGN_CENTER); - gtk_widget_set_halign(GTK_WIDGET(box), GTK_ALIGN_CENTER); - - instance_name_box = gtk_entry_new(); - gtk_entry_set_placeholder_text( - GTK_ENTRY(instance_name_box), "Instance domain"); - g_signal_connect(GTK_ENTRY(instance_name_box), "activate", - G_CALLBACK(form_on_activate), NULL); - g_signal_connect(G_OBJECT(instance_name_box), "changed", - G_CALLBACK(on_form_changed), NULL); + GtkBuilder *login_builder; - email_box = gtk_entry_new(); - gtk_entry_set_placeholder_text(GTK_ENTRY(email_box), "Email"); - gtk_entry_set_input_purpose(GTK_ENTRY(email_box), GTK_INPUT_PURPOSE_EMAIL); - g_signal_connect(GTK_ENTRY(email_box), "activate", + login_builder = gtk_builder_new_from_file("data/login_window.ui"); + login_dialog = gtk_builder_get_object(login_builder, "login_dialog"); + + instance_domain_entry = gtk_builder_get_object(login_builder, "instance_name"); + g_signal_connect(G_OBJECT(instance_domain_entry), "changed", + G_CALLBACK(login_form_changed), NULL); + g_signal_connect(GTK_ENTRY(instance_domain_entry), "activate", G_CALLBACK(form_on_activate), NULL); - g_signal_connect( - G_OBJECT(email_box), "changed", G_CALLBACK(on_form_changed), NULL); - - password_box = gtk_entry_new(); - gtk_entry_set_placeholder_text(GTK_ENTRY(password_box), "Password"); - gtk_entry_set_input_purpose( - GTK_ENTRY(password_box), GTK_INPUT_PURPOSE_PASSWORD); - gtk_entry_set_visibility(GTK_ENTRY(password_box), false); - g_signal_connect(GTK_ENTRY(password_box), "activate", + + email_entry = gtk_builder_get_object(login_builder, "email"); + g_signal_connect(G_OBJECT(email_entry), "changed", + G_CALLBACK(login_form_changed), NULL); + g_signal_connect(GTK_ENTRY(email_entry), "activate", G_CALLBACK(form_on_activate), NULL); - g_signal_connect(G_OBJECT(password_box), "changed", - G_CALLBACK(on_form_changed), NULL); - submit_button = gtk_button_new(); - g_signal_connect(GTK_BUTTON(submit_button), "clicked", - G_CALLBACK(submit_button_clicked), G_OBJECT(window)); - gtk_button_set_label(GTK_BUTTON(submit_button), "Submit"); - gtk_widget_set_sensitive(GTK_WIDGET(submit_button), false); + password_entry = gtk_builder_get_object(login_builder, "password"); + g_signal_connect(G_OBJECT(password_entry), "changed", + G_CALLBACK(login_form_changed), NULL); + g_signal_connect(GTK_ENTRY(password_entry), "activate", + G_CALLBACK(form_on_activate), NULL); - spinner = gtk_spinner_new(); + login_button = gtk_builder_get_object(login_builder, "login_button"); + g_signal_connect(GTK_BUTTON(login_button), "clicked", + G_CALLBACK(login_button_click), NULL); + cancel_button = gtk_builder_get_object(login_builder, "cancel_button"); - gtk_container_add(GTK_CONTAINER(window), box); - gtk_container_add(GTK_CONTAINER(box), instance_name_box); - gtk_container_add(GTK_CONTAINER(box), email_box); - gtk_container_add(GTK_CONTAINER(box), password_box); - gtk_container_add(GTK_CONTAINER(box), submit_button); - gtk_container_add(GTK_CONTAINER(box), spinner); + spinner = gtk_builder_get_object(login_builder, "spinner"); - gtk_widget_show_all(window); + return gtk_dialog_run(GTK_DIALOG(login_dialog)); } diff --git a/src/login_window.h b/src/login_window.h index cf879cc..b3d299d 100644 --- a/src/login_window.h +++ b/src/login_window.h @@ -1,7 +1,7 @@ #ifndef __LOGIN_WINDOW_H #define __LOGIN_WINDOW_H -void create_login_window(GtkApplication *app, gpointer user_data); +int create_login_dialog(); #endif diff --git a/src/main.c b/src/main.c index d95f547..78968a3 100644 --- a/src/main.c +++ b/src/main.c @@ -4,13 +4,9 @@ #include #include #include -#include "auth.h" #include "http.h" -#include "timeline.h" -#include "login_window.h" #include "config.h" -#include "timeline_window.h" -#include "log.h" +#include "main_window.h" static void startup(GtkApplication *app, gpointer user_data) { @@ -22,11 +18,7 @@ static void startup(GtkApplication *app, gpointer user_data) static void activate(GtkApplication *app, gpointer user_data) { - if (read_local_credentials()) { - create_login_window(app, user_data); - return; - } - create_timeline_window(app, NULL); + create_main_window(app, NULL); } int main(int argc, char **argv) diff --git a/src/main_window.c b/src/main_window.c new file mode 100644 index 0000000..048de51 --- /dev/null +++ b/src/main_window.c @@ -0,0 +1,167 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include "auth.h" +#include "http.h" +#include "timeline.h" +#include "log.h" +#include "config.h" +#include "login_window.h" +#include "string-util.h" + +static GtkWidget *window, *scrolled, *list_box; + +static gchar *html_to_pango(const char *content) +{ + gchar *result1, *result2; + GRegex *regex_tag, *regex_attr; + GError *error = NULL; + + if (!content) { + return NULL; + } + + regex_tag = g_regex_new( + "(

|

|

|
|
)", G_REGEX_CASELESS, 0, &error); + if (!regex_tag) { + log_msg(LOG_WARNING, "html_to_pango", error->message); + g_free(error); + return NULL; + } + + result1 = g_regex_replace(regex_tag, content, -1, 0, "", 0, &error); + if (!result1) { + log_msg(LOG_WARNING, "html_to_pango", error->message); + g_free(error); + return NULL; + } + + regex_attr = + g_regex_new("(class|target|rel|data-user|data-tag)=\"(.|\n)*?\"", + G_REGEX_CASELESS, 0, &error); + if (!regex_attr) { + log_msg(LOG_WARNING, "html_to_pango", error->message); + g_free(error); + return NULL; + } + + result2 = g_regex_replace(regex_attr, result1, -1, 0, "", 0, &error); + free(result1); + if (!result1) { + log_msg(LOG_WARNING, "html_to_pango", error->message); + g_free(error); + return NULL; + } + + return result2; +} + +static gboolean timeline_loaded(gpointer data) +{ + struct timeline *t = data; + for (size_t i = 0; i < t->size; i++) { + GtkBuilder *post_builder; + GObject *post_box, *post_content_label; + GObject *display_name, *username; + GObject *replies_count, *reblogs_count, *favourites_count; + GObject *avatar; + GdkPixbuf *avatar_pixbuf; + char *content_markup; + + content_markup = html_to_pango(t->statuses[i]->content); + if (!content_markup) { + continue; + } + + post_builder = gtk_builder_new_from_file("data/post.ui"); + + post_box = gtk_builder_get_object(post_builder, "post_box"); + post_content_label = + gtk_builder_get_object(post_builder, "content_text"); + gtk_label_set_markup(GTK_LABEL(post_content_label), content_markup); + + avatar = gtk_builder_get_object(post_builder, "avatar"); + avatar_pixbuf = + gdk_pixbuf_new_from_file_at_size("data/avi.png", 40, 40, NULL); + gtk_image_set_from_pixbuf(GTK_IMAGE(avatar), avatar_pixbuf); + + display_name = gtk_builder_get_object(post_builder, "display_name"); + gtk_label_set_text( + GTK_LABEL(display_name), t->statuses[i]->account->display_name); + + username = gtk_builder_get_object(post_builder, "username"); + gtk_label_set_text( + GTK_LABEL(username), t->statuses[i]->account->username); + + replies_count = gtk_builder_get_object(post_builder, "replies_count"); + gchar *repc = g_strdup_printf("%d", t->statuses[i]->replies_count); + gtk_label_set_text(GTK_LABEL(replies_count), repc); + g_free(repc); + + reblogs_count = gtk_builder_get_object(post_builder, "reblogs_count"); + gchar *rebc = g_strdup_printf("%d", t->statuses[i]->reblogs_count); + gtk_label_set_text(GTK_LABEL(reblogs_count), rebc); + g_free(rebc); + + favourites_count = + gtk_builder_get_object(post_builder, "favourites_count"); + gchar *fc = g_strdup_printf("%d", t->statuses[i]->favourites_count); + gtk_label_set_text(GTK_LABEL(favourites_count), fc); + g_free(fc); + + gtk_list_box_prepend(GTK_LIST_BOX(list_box), GTK_WIDGET(post_box)); + gtk_widget_show_all(GTK_WIDGET(post_box)); + } + /* gtk_spinner_stop(GTK_SPINNER(spinner)); */ + timeline_free(t); + return G_SOURCE_REMOVE; +} + +static gpointer load_timeline(gpointer data) +{ + struct timeline *t; + t = get_timeline(NULL, NULL, NULL, 20); + if (!t) { + log_msg(LOG_WARNING, "load_timeline", "failed"); + return NULL; + } + gdk_threads_add_idle(timeline_loaded, t); + return NULL; +} + +void create_main_window(GtkApplication *app, gpointer user_data) +{ + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_application(GTK_WINDOW(window), GTK_APPLICATION(app)); + gtk_window_set_title(GTK_WINDOW(window), "ap_client"); + gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); + gtk_container_set_border_width(GTK_CONTAINER(window), 10); + + scrolled = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + list_box = gtk_list_box_new(); + gtk_widget_set_valign(GTK_WIDGET(list_box), GTK_ALIGN_CENTER); + gtk_widget_set_halign(GTK_WIDGET(list_box), GTK_ALIGN_CENTER); + + /* spinner = gtk_spinner_new(); */ + /* gtk_spinner_start(GTK_SPINNER(spinner)); */ + /* gtk_container_add(GTK_CONTAINER(list_box), spinner); */ + + gtk_container_add(GTK_CONTAINER(window), scrolled); + gtk_container_add(GTK_CONTAINER(scrolled), list_box); + gtk_widget_show_all(window); + + if (!is_logged_in()) { + create_login_dialog(); + } + if (!is_logged_in()) { + log_msg(LOG_ERROR, "create_main_window", + "login is required to view timeline"); + } + g_thread_new("load_timeline_thread", &load_timeline, NULL); +} diff --git a/src/main_window.h b/src/main_window.h new file mode 100644 index 0000000..3a2059e --- /dev/null +++ b/src/main_window.h @@ -0,0 +1,9 @@ +#ifndef __MAIN_WINDOW_H +#define __MAIN_WINDOW_H + +void create_main_window (GtkApplication *app, gpointer user_data); + +#endif + + + diff --git a/src/status.c b/src/status.c index 69d1fa2..cfb3645 100644 --- a/src/status.c +++ b/src/status.c @@ -3,6 +3,7 @@ #include #include #include "status.h" +#include "account.h" #include "log.h" struct status *status_from_json(const char *json_data) @@ -57,6 +58,11 @@ struct status *status_from_json_t(const json_t *root) s->url = strdup(json_string_value(url)); } + json_t *account = json_object_get(root, "account"); + if (json_is_object(account)) { + s->account = account_from_json_t(account); + } + json_t *in_reply_to_id = json_object_get(root, "in_reply_to_id"); if (json_is_string(in_reply_to_id)) { s->in_reply_to_id = strdup(json_string_value(in_reply_to_id)); @@ -100,6 +106,8 @@ void status_free(struct status *s) free(s->uri); if (s->url) free(s->url); + if (s->account) + account_free(s->account); if (s->in_reply_to_id) free(s->in_reply_to_id); if (s->in_reply_to_account_id) diff --git a/src/timeline.c b/src/timeline.c index be1a4c4..4cd9fe0 100644 --- a/src/timeline.c +++ b/src/timeline.c @@ -102,7 +102,6 @@ struct timeline *get_timeline(const char *max_id, const char *since_id, const ch return NULL; } - printf("url: %s\n", url); resp = get_request(url); free(url); if (!resp) { diff --git a/src/timeline_window.c b/src/timeline_window.c deleted file mode 100644 index 4b17824..0000000 --- a/src/timeline_window.c +++ /dev/null @@ -1,120 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include "auth.h" -#include "http.h" -#include "timeline.h" -#include "log.h" -#include "string-util.h" - -static GtkWidget *window, *scrolled, *list_box; - -static gchar *html_to_pango(const char *content) -{ - char *str1, *str2; - gchar *result; - GRegex *regex = NULL; - GError *error = NULL; - - if (!content) { - return NULL; - } - - str1 = str_replace(content, "

", ""); - if (!str1) { - log_msg(LOG_WARNING, "html_to_pango", "failed to parse html"); - return NULL; - } - str2 = str_replace(str1, "

", ""); - free(str1); - if (!str2) { - log_msg(LOG_WARNING, "html_to_pango", "failed to parse html"); - return NULL; - } - - regex = g_regex_new("(class|target|rel)=\"(.|\n)*?\"", G_REGEX_CASELESS, 0, &error); - if (!regex) { - log_msg(LOG_WARNING, "html_to_pango", error->message); - g_free(error); - return NULL; - } - - result = g_regex_replace(regex, str2, -1, 0, "", 0, &error); - free(str2); - if (!result) { - log_msg(LOG_WARNING, "html_to_pango", error->message); - g_free(error); - return NULL; - } - - return result; -} - -static gboolean timeline_loaded(gpointer data) -{ - struct timeline *t = data; - for (size_t i = 0; i < t->size; i++) { - GtkBuilder *post_builder; - GObject *post_box, *post_content_label; - char *content_markup; - - content_markup = html_to_pango(t->statuses[i]->content); - if (!content_markup) { - continue; - } - - post_builder = gtk_builder_new_from_file("data/post.ui"); - - post_box = gtk_builder_get_object(post_builder, "post_box"); - post_content_label = gtk_builder_get_object(post_builder, "content_text"); - gtk_label_set_markup(GTK_LABEL(post_content_label), content_markup); - - gtk_list_box_prepend(GTK_LIST_BOX(list_box), GTK_WIDGET(post_box)); - gtk_widget_show_all(GTK_WIDGET(post_box)); - } - /* gtk_spinner_stop(GTK_SPINNER(spinner)); */ - timeline_free(t); - return G_SOURCE_REMOVE; -} - -static gpointer load_timeline(gpointer data) -{ - struct timeline *t; - t = get_timeline(NULL, NULL, NULL, 20); - if (!t) { - log_msg(LOG_WARNING, "load_timeline", "failed"); - return NULL; - } - gdk_threads_add_idle(timeline_loaded, t); - return NULL; -} - -void create_timeline_window(GtkApplication *app, gpointer user_data) -{ - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_application(GTK_WINDOW(window), GTK_APPLICATION(app)); - gtk_window_set_title(GTK_WINDOW(window), "ap_client"); - gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); - gtk_container_set_border_width(GTK_CONTAINER(window), 10); - - scrolled = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - - list_box = gtk_list_box_new(); - gtk_widget_set_valign(GTK_WIDGET(list_box), GTK_ALIGN_CENTER); - gtk_widget_set_halign(GTK_WIDGET(list_box), GTK_ALIGN_CENTER); - - /* spinner = gtk_spinner_new(); */ - /* gtk_spinner_start(GTK_SPINNER(spinner)); */ - /* gtk_container_add(GTK_CONTAINER(list_box), spinner); */ - - gtk_container_add(GTK_CONTAINER(window), scrolled); - gtk_container_add(GTK_CONTAINER(scrolled), list_box); - gtk_widget_show_all(window); - - g_thread_new("load_timeline_thread", &load_timeline, NULL); -} diff --git a/src/timeline_window.h b/src/timeline_window.h deleted file mode 100644 index 8aff454..0000000 --- a/src/timeline_window.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __TIMELINE_WINDOW_H -#define __TIMELINE_WINDOW_H - -void create_timeline_window (GtkApplication *app, gpointer user_data); - -#endif - - - -- cgit v1.2.3