Skip to content

Commit bf55dc9

Browse files
committed
Port TweetListBox to C
1 parent 5c448f1 commit bf55dc9

18 files changed

+330
-218
lines changed

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ corebird_lib_sources = files([
128128
'src/widgets/ReplyEntry.vala',
129129
'src/widgets/ReplyIndicator.vala',
130130
'src/widgets/ScrollWidget.vala',
131-
'src/widgets/TweetListBox.vala',
132131
'src/widgets/UserListsWidget.vala',
133132
'src/widgets/FavImageView.vala',
134133
'src/window/AboutDialog.vala',
@@ -170,6 +169,7 @@ corebird_lib_sources = files([
170169
'src/CbQuoteTweetWidget.c',
171170
'src/CbAspectImage.c',
172171
'src/CbTextButton.c',
172+
'src/CbTweetListBox.c',
173173

174174
# Rest sources
175175
'src/rest/rest/rest-param.c',

src/CbTweetListBox.c

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
/* This file is part of corebird, a Gtk+ linux Twitter client.
2+
* Copyright (C) 2018 Timm Bäder
3+
*
4+
* corebird is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* corebird is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with corebird. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include <glib/gi18n.h>
19+
#include "CbTweetListBox.h"
20+
#include "CbTweetRow.h"
21+
#include "corebird.h"
22+
23+
G_DEFINE_TYPE (CbTweetListBox, cb_tweet_list_box, GTK_TYPE_LIST_BOX);
24+
25+
enum {
26+
RETRY_BUTTON_CLICKED,
27+
LAST_SIGNAL
28+
};
29+
static guint tweet_list_box_signals[LAST_SIGNAL] = { 0 };
30+
31+
32+
static GtkWidget *
33+
tweet_row_create_func (gpointer item,
34+
gpointer user_data)
35+
{
36+
g_assert (CB_IS_TWEET (item));
37+
38+
return cb_tweet_row_new (CB_TWEET (item),
39+
MAIN_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (user_data))));
40+
}
41+
42+
static void
43+
gesture_pressed_cb (GtkGestureMultiPress *gesture,
44+
int n_press,
45+
double x,
46+
double y,
47+
gpointer user_data)
48+
{
49+
CbTweetListBox *self = user_data;
50+
51+
g_message (__FUNCTION__);
52+
}
53+
54+
static void
55+
double_click_activation_setting_changed_cb (GObject *obj,
56+
GParamSpec *pspec,
57+
gpointer user_data)
58+
{
59+
CbTweetListBox *self = user_data;
60+
GSettings *settings = G_SETTINGS (obj);
61+
62+
gtk_list_box_set_activate_on_single_click ((GtkListBox *)self,
63+
!g_settings_get_boolean (settings, "double-click-activation"));
64+
}
65+
66+
static void
67+
retry_button_clicked_cb (GtkButton *source,
68+
gpointer user_data)
69+
{
70+
g_signal_emit (user_data, tweet_list_box_signals[RETRY_BUTTON_CLICKED], 0);
71+
}
72+
73+
static void
74+
cb_tweet_list_box_finalize (GObject *obj)
75+
{
76+
CbTweetListBox *self = (CbTweetListBox *)obj;
77+
78+
g_object_unref (self->delta_updater);
79+
g_object_unref (self->multipress_gesture);
80+
g_object_unref (self->model);
81+
82+
G_OBJECT_CLASS (cb_tweet_list_box_parent_class)->finalize (obj);
83+
}
84+
85+
static void
86+
cb_tweet_list_box_class_init (CbTweetListBoxClass *klass)
87+
{
88+
GtkBindingSet *binding_set;
89+
GObjectClass *object_class = (GObjectClass *)klass;
90+
91+
/* vfuncs */
92+
object_class->finalize = cb_tweet_list_box_finalize;
93+
94+
/* signals */
95+
tweet_list_box_signals[RETRY_BUTTON_CLICKED] = g_signal_new ("retry-button-clicked",
96+
G_OBJECT_CLASS_TYPE (object_class),
97+
G_SIGNAL_RUN_FIRST,
98+
0,
99+
NULL, NULL,
100+
NULL, G_TYPE_NONE, 0);
101+
/* key bindings */
102+
binding_set = gtk_binding_set_by_class (klass);
103+
// TODO :(
104+
}
105+
106+
static void
107+
cb_tweet_list_box_init (CbTweetListBox *self)
108+
{
109+
gtk_style_context_add_class (gtk_widget_get_style_context ((GtkWidget *)self), "tweets");
110+
gtk_list_box_set_selection_mode ((GtkListBox *)self, GTK_SELECTION_NONE);
111+
gtk_list_box_set_activate_on_single_click ((GtkListBox *)self,
112+
!g_settings_get_boolean ((GSettings *)settings_get (),
113+
"double-click-activation"));
114+
115+
self->model = cb_tweet_model_new ();
116+
self->delta_updater = cb_delta_updater_new ((GtkWidget *)self);
117+
self->multipress_gesture = gtk_gesture_multi_press_new ((GtkWidget *)self);
118+
gtk_gesture_single_set_button ((GtkGestureSingle *)self->multipress_gesture, 0);
119+
gtk_event_controller_set_propagation_phase ((GtkEventController *)self->multipress_gesture,
120+
GTK_PHASE_BUBBLE);
121+
g_signal_connect (self->multipress_gesture, "pressed", G_CALLBACK (gesture_pressed_cb), self);
122+
123+
g_signal_connect (settings_get (), "changed::double-click-activation",
124+
G_CALLBACK (double_click_activation_setting_changed_cb), self);
125+
126+
gtk_list_box_bind_model ((GtkListBox *)self,
127+
(GListModel *)self->model,
128+
tweet_row_create_func,
129+
self,
130+
NULL);
131+
132+
/* Create some pre-defined placeholder widgetry */
133+
{
134+
GtkWidget *loading_label;
135+
GtkWidget *error_box;
136+
GtkWidget *retry_button;
137+
138+
self->placeholder = gtk_stack_new ();
139+
gtk_stack_set_transition_type ((GtkStack *)self->placeholder, GTK_STACK_TRANSITION_TYPE_CROSSFADE);
140+
141+
loading_label = gtk_label_new (_("Loading…"));
142+
gtk_style_context_add_class (gtk_widget_get_style_context (loading_label), "dim-label");
143+
gtk_stack_add_named ((GtkStack *)self->placeholder, loading_label, "spinner");
144+
145+
self->no_entries_label = gtk_label_new (_("No entries found"));
146+
gtk_style_context_add_class (gtk_widget_get_style_context (self->no_entries_label), "dim-label");
147+
gtk_label_set_line_wrap_mode ((GtkLabel *)self->no_entries_label, PANGO_WRAP_WORD_CHAR);
148+
gtk_stack_add_named ((GtkStack *)self->placeholder, self->no_entries_label, "no-entries");
149+
150+
error_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
151+
retry_button = gtk_button_new_with_label (_("Retry"));
152+
self->error_label = gtk_label_new ("");
153+
gtk_style_context_add_class (gtk_widget_get_style_context (self->error_label), "dim-label");
154+
gtk_label_set_line_wrap_mode ((GtkLabel *)self->error_label, PANGO_WRAP_WORD_CHAR);
155+
gtk_widget_set_margin_top (self->error_label, 12);
156+
gtk_widget_set_margin_end (self->error_label, 12);
157+
gtk_widget_set_margin_bottom (self->error_label, 12);
158+
gtk_widget_set_margin_start (self->error_label, 12);
159+
gtk_label_set_selectable ((GtkLabel *)self->error_label, TRUE);
160+
gtk_container_add (GTK_CONTAINER (error_box), self->error_label);
161+
gtk_widget_set_halign (retry_button, GTK_ALIGN_CENTER);
162+
g_signal_connect (retry_button, "clicked", G_CALLBACK (retry_button_clicked_cb), self);
163+
gtk_container_add (GTK_CONTAINER (error_box), retry_button);
164+
gtk_stack_add_named ((GtkStack *)self->placeholder, error_box, "error");
165+
166+
gtk_stack_set_visible_child_name ((GtkStack *)self->placeholder, "spinner");
167+
gtk_widget_set_halign (self->placeholder, GTK_ALIGN_CENTER);
168+
gtk_widget_set_valign (self->placeholder, GTK_ALIGN_CENTER);
169+
gtk_list_box_set_placeholder ((GtkListBox *)self, self->placeholder);
170+
}
171+
}
172+
173+
GtkWidget *
174+
cb_tweet_list_box_new (void)
175+
{
176+
return GTK_WIDGET (g_object_new (CB_TYPE_TWEET_LIST_BOX, NULL));
177+
}
178+
179+
void
180+
cb_tweet_list_box_set_empty (CbTweetListBox *self)
181+
{
182+
gtk_stack_set_visible_child_name ((GtkStack *)self->placeholder, "no-entries");
183+
}
184+
185+
void
186+
cb_tweet_list_box_set_unempty (CbTweetListBox *self)
187+
{
188+
gtk_stack_set_visible_child_name ((GtkStack *)self->placeholder, "spinner");
189+
}
190+
191+
void
192+
cb_tweet_list_box_set_error (CbTweetListBox *self,
193+
const char *error_message)
194+
{
195+
gtk_label_set_label (GTK_LABEL (self->error_label), error_message);
196+
gtk_stack_set_visible_child_name ((GtkStack *)self->placeholder, "error");
197+
}
198+
199+
void
200+
cb_tweet_list_box_set_placeholder_text (CbTweetListBox *self,
201+
const char *placeholder_text)
202+
{
203+
gtk_label_set_label (GTK_LABEL (self->no_entries_label), placeholder_text);
204+
}
205+
206+
void
207+
cb_tweet_list_box_reset_placeholder_text (CbTweetListBox *self)
208+
{
209+
gtk_label_set_label (GTK_LABEL (self->no_entries_label), _("No entries found"));
210+
}
211+
212+
GtkWidget *
213+
cb_tweet_list_box_get_first_visible_row (CbTweetListBox *self)
214+
{
215+
return NULL;
216+
}
217+
218+
GtkWidget *
219+
cb_tweet_list_box_get_placeholder (CbTweetListBox *self)
220+
{
221+
return self->placeholder;
222+
}
223+
224+
225+
void
226+
cb_tweet_list_box_remove_all (CbTweetListBox *self)
227+
{
228+
229+
}

src/CbTweetListBox.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* This file is part of corebird, a Gtk+ linux Twitter client.
2+
* Copyright (C) 2018 Timm Bäder
3+
*
4+
* corebird is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* corebird is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with corebird. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#ifndef __CB_TWEET_LIST_BOX_H__
19+
#define __CB_TWEET_LIST_BOX_H__
20+
21+
#include <gtk/gtk.h>
22+
#include "CbDeltaUpdater.h"
23+
#include "CbTweetModel.h"
24+
25+
typedef struct _CbTweetListBox CbTweetListBox;
26+
struct _CbTweetListBox
27+
{
28+
GtkListBox parent_instance;
29+
30+
CbTweetModel *model;
31+
CbDeltaUpdater *delta_updater;
32+
GtkGesture *multipress_gesture;
33+
GtkWidget *placeholder;
34+
GtkWidget *error_label;
35+
GtkWidget *no_entries_label;
36+
37+
GtkWidget *action_entry;
38+
};
39+
40+
#define CB_TYPE_TWEET_LIST_BOX cb_tweet_list_box_get_type ()
41+
G_DECLARE_FINAL_TYPE (CbTweetListBox, cb_tweet_list_box, CB, TWEET_LIST_BOX, GtkListBox);
42+
43+
GtkWidget * cb_tweet_list_box_new (void);
44+
void cb_tweet_list_box_set_empty (CbTweetListBox *self);
45+
void cb_tweet_list_box_set_unempty (CbTweetListBox *self);
46+
void cb_tweet_list_box_set_error (CbTweetListBox *self,
47+
const char *error_message);
48+
void cb_tweet_list_box_set_placeholder_text (CbTweetListBox *self,
49+
const char *placeholder_text);
50+
void cb_tweet_list_box_reset_placeholder_text (CbTweetListBox *self);
51+
GtkWidget * cb_tweet_list_box_get_first_visible_row (CbTweetListBox *self);
52+
GtkWidget * cb_tweet_list_box_get_placeholder (CbTweetListBox *self);
53+
void cb_tweet_list_box_remove_all (CbTweetListBox *self);
54+
55+
56+
57+
58+
#endif

src/DefaultTimeline.vala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public abstract class DefaultTimeline : ScrollWidget, IPage {
3737
_main_window = value;
3838
}
3939
}
40-
public TweetListBox tweet_list = new TweetListBox ();
40+
public Cb.TweetListBox tweet_list = new Cb.TweetListBox ();
4141
public unowned Account account;
4242
protected BadgeRadioButton radio_button;
4343
protected uint tweet_remove_timeout = 0;

src/FavoritesTimeline.vala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class FavoritesTimeline : Cb.MessageReceiver, DefaultTimeline {
2525
public FavoritesTimeline (int id, Account account) {
2626
base (id);
2727
this.account = account;
28-
this.tweet_list.account = account;
28+
//this.tweet_list.account = account;
2929
}
3030

3131
private void stream_message_received (Cb.StreamMessageType type, Json.Node root) {

src/HomeTimeline.vala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class HomeTimeline : Cb.MessageReceiver, DefaultTimeline {
2525
public HomeTimeline(int id, Account account) {
2626
base (id);
2727
this.account = account;
28-
this.tweet_list.account = account;
28+
//this.tweet_list.account = account;
2929
}
3030

3131
public void stream_message_received (Cb.StreamMessageType type, Json.Node root) {

src/ListStatusesPage.vala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class ListStatusesPage : ScrollWidget, IPage {
3838
private int64 list_id;
3939
private uint tweet_remove_timeout = 0;
4040
[GtkChild]
41-
private TweetListBox tweet_list;
41+
private Cb.TweetListBox tweet_list;
4242
[GtkChild]
4343
private MaxSizeContainer max_size_container;
4444
[GtkChild]
@@ -87,7 +87,7 @@ class ListStatusesPage : ScrollWidget, IPage {
8787
public ListStatusesPage (int id, Account account) {
8888
this.id = id;
8989
this.account = account;
90-
this.tweet_list.account = account;
90+
//this.tweet_list.account = account;
9191
this.scroll_event.connect (scroll_event_cb);
9292
this.scrolled_to_end.connect (load_older);
9393
this.scrolled_to_start.connect (handle_scrolled_to_start);

src/MentionsTimeline.vala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class MentionsTimeline : Cb.MessageReceiver, DefaultTimeline {
2525
public MentionsTimeline(int id, Account account) {
2626
base (id);
2727
this.account = account;
28-
this.tweet_list.account= account;
28+
//this.tweet_list.account= account;
2929
}
3030

3131
private void stream_message_received (Cb.StreamMessageType type, Json.Node root) {

src/ProfilePage.vala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ public class ProfilePage : ScrollWidget, IPage, Cb.MessageReceiver {
6363
[GtkChild]
6464
private FollowButton follow_button;
6565
[GtkChild]
66-
private TweetListBox tweet_list;
66+
private Cb.TweetListBox tweet_list;
6767
[GtkChild]
68-
private TweetListBox followers_list;
68+
private Cb.TweetListBox followers_list;
6969
[GtkChild]
70-
private TweetListBox following_list;
70+
private Cb.TweetListBox following_list;
7171
[GtkChild]
7272
private Gtk.Spinner progress_spinner;
7373
[GtkChild]
@@ -105,7 +105,7 @@ public class ProfilePage : ScrollWidget, IPage, Cb.MessageReceiver {
105105
this.id = id;
106106
this.account = account;
107107
this.user_lists.account = account;
108-
this.tweet_list.account = account;
108+
//this.tweet_list.account = account;
109109

110110
this.scrolled_to_end.connect (() => {
111111
if (user_stack.visible_child == tweet_list) {

src/SearchPage.vala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class SearchPage : IPage, Gtk.Box {
3737
[GtkChild]
3838
private Gtk.Button search_button;
3939
[GtkChild]
40-
private TweetListBox tweet_list;
40+
private Cb.TweetListBox tweet_list;
4141
[GtkChild]
4242
private Gtk.Label users_header;
4343
[GtkChild]

0 commit comments

Comments
 (0)