Skip to content

Commit 3e5891d

Browse files
GeopJralice-mkh
andauthored
feat(profile): better filter UX (#1189)
Co-authored-by: Alice Mikhaylenko <[email protected]>
1 parent 2e6d66c commit 3e5891d

9 files changed

+217
-73
lines changed

data/gresource.xml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<gresource prefix="/dev/geopjr/Tuba/">
44
<file>style.css</file>
55
<file>style-dark.css</file>
6+
<file>style-hc.css</file>
67

78
<file preprocess="xml-stripblanks">icons/scalable/actions/tuba-hashtag-symbolic.svg</file>
89
<file preprocess="xml-stripblanks">icons/scalable/actions/tuba-bookmarks-symbolic.svg</file>

data/style-hc.css

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.ttl-profile-cover.thanks {
2+
background: alpha(@accent_bg_color, 0.08);
3+
}
4+
5+
.ttl-profile-cover.thanks avatar {
6+
border-color: alpha(@accent_bg_color, 0.08);
7+
}
8+
9+
.toggle-group-17 {
10+
box-shadow: inset 0 0 0 1px var(--border-color);
11+
}
12+
13+
.toggle-group-17 button:checked {
14+
box-shadow: inset 0 0 0 1px var(--border-color),
15+
0 1px 3px 1px rgb(0 0 0 / 7%),
16+
0 2px 6px 2px rgb(0 0 0 / 3%);
17+
}

data/style.css

+41-9
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ headerbar.flat.no-title .title {
300300
background-color: alpha(@warning_bg_color, .1);
301301
}
302302

303-
.ttl-post.direct:hover{
303+
.ttl-post.direct:hover {
304304
background-color: darker(alpha(@warning_bg_color, .1));
305305
}
306306

@@ -336,7 +336,7 @@ headerbar.flat.no-title .title {
336336
.about .app-version:hover{background:radial-gradient(circle at 9.75% 50%,#0000 6.66%,#7902aa 6.7%,#0000 8.4%),conic-gradient(at 26.66% 50%,#0000 222.75deg,#ffd800 0 317.25deg,#0000 0),conic-gradient(at 33% 50%,#0000 222.75deg,white 0 317.25deg,#0000 0),conic-gradient(at 39% 50%,#0000 222.75deg,#ffa6b9 0 317.25deg,#0000 0),conic-gradient(at 45.66% 50%,#0000 222.75deg,#00d2ff 0 317.25deg,#0000 0),conic-gradient(at 52% 50%,#0000 222.75deg,#753000 0 317.25deg,#0000 0),conic-gradient(at 58.33% 50%,#0000 222.75deg,#000 0 317.25deg,#0000 0),linear-gradient(to bottom,#e40303,#e40303 16.67%,#ff8c00 16.67%,#ff8c00 33.33%,#ffed00 33.33%,#ffed00 50%,#008026 50%,#008026 66.67%,#004dff 66.67%,#004dff 83.33%,#750787 83.33%,#750787);}
337337

338338
/* Composer auto completion */
339-
GtkSourceAssistant.completion list row{
339+
GtkSourceAssistant.completion list row {
340340
padding: 6px 12px 6px 12px;
341341
}
342342

@@ -433,12 +433,12 @@ video > overlay > revealer > controls, .audio-controls {
433433
animation: loadbg 0.5s ease;
434434
}
435435

436-
.ttl-poll-row:first-child{
436+
.ttl-poll-row:first-child {
437437
border-top-left-radius: 12px;
438438
border-top-right-radius: 12px;
439439
}
440440

441-
.ttl-poll-row:last-child{
441+
.ttl-poll-row:last-child {
442442
border-bottom-left-radius: 12px;
443443
border-bottom-right-radius: 12px;
444444
}
@@ -477,7 +477,7 @@ video > overlay > revealer > controls, .audio-controls {
477477

478478
.ttl-view listview>row.activatable:selected:hover,
479479
.ttl-view listview>row.activatable:hover {
480-
background-color:transparent;
480+
background-color: transparent;
481481
}
482482

483483
.ttl-view listview>row.activatable:selected:active,
@@ -496,7 +496,8 @@ video > overlay > revealer > controls, .audio-controls {
496496
}
497497

498498
/* .ttl-view .small.content .card { */
499-
.ttl-view .small.fake-content .card {
499+
.ttl-view .small.fake-content .card,
500+
.ttl-view .small.fake-content .toggle-group-17 {
500501
border-left: none;
501502
border-right: none;
502503
border-radius: 0px;
@@ -508,7 +509,7 @@ video > overlay > revealer > controls, .audio-controls {
508509
}
509510

510511
/* .ttl-view .content row:not(.ttl-post) { */
511-
.ttl-view .fake-content row:not(.ttl-post) {
512+
.ttl-view .fake-content row:not(.ttl-post):not(.toggle-group-17) {
512513
padding: 0px;
513514
}
514515

@@ -558,6 +559,7 @@ video > overlay > revealer > controls, .audio-controls {
558559
.ttl-view .small.fake-content .card {
559560
box-shadow: none;
560561
}
562+
561563
.ttl-view .small .preview_card.explore .preview_card_h {
562564
border-radius: 0px;
563565
}
@@ -660,7 +662,8 @@ video > overlay > revealer > controls, .audio-controls {
660662
font-size: small;
661663
}
662664

663-
.preview_card:not(.explore), .preview_card:not(.explore) image:not(.attachment-overlay-icon) {
665+
.preview_card:not(.explore),
666+
.preview_card:not(.explore) image:not(.attachment-overlay-icon) {
664667
background-color: alpha(currentColor, 0.0625);
665668
}
666669

@@ -767,7 +770,8 @@ list.uniform-border-color row {
767770
border-bottom-color: @borders;
768771
}
769772

770-
.emoji-reaction-expander > box > list, .emoji-reaction-expander > box > list > row {
773+
.emoji-reaction-expander>box>list,
774+
.emoji-reaction-expander>box>list>row {
771775
border-radius: inherit;
772776
}
773777

@@ -778,3 +782,31 @@ list.uniform-border-color row {
778782
.ttl-profile-cover.thanks avatar {
779783
border-color: alpha(@accent_bg_color, 0.1);
780784
}
785+
786+
.toggle-group-17 {
787+
background: color-mix(in srgb, currentColor 10%, transparent);
788+
border-radius: 9px;
789+
padding: 3px;
790+
}
791+
792+
.toggle-group-17 button {
793+
padding: 2px 15px;
794+
transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
795+
transition-property: outline-color, outline-width, outline-offset, background, box-shadow;
796+
}
797+
798+
.toggle-group-17 button:checked {
799+
background: rgb(from var(--card-bg-color) r g b / calc(alpha * 2));
800+
color: var(--card-fg-color);
801+
box-shadow: 0 1px 3px 1px rgb(0 0 0 / 7%),
802+
0 2px 6px 2px rgb(0 0 0 / 3%);
803+
}
804+
805+
.toggle-group-17 separator {
806+
margin: 3px 1px;
807+
transition: opacity 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
808+
}
809+
810+
.toggle-group-17 separator.hidden {
811+
opacity: 0;
812+
}

data/ui/menus.ui

-33
Original file line numberDiff line numberDiff line change
@@ -65,39 +65,6 @@
6565

6666
<section>
6767
<attribute name="label" translatable="yes">Timeline</attribute>
68-
<submenu id="profile-filter-menu">
69-
<attribute name="label" translatable="yes">Filter</attribute>
70-
<!-- <item>
71-
<attribute name="label" translatable="yes">Posts</attribute>
72-
<attribute name="action">view.source</attribute>
73-
<attribute name="target">statuses</attribute>
74-
</item>
75-
<item>
76-
<attribute name="label" translatable="yes">Following</attribute>
77-
<attribute name="action">view.source</attribute>
78-
<attribute name="target">following</attribute>
79-
</item>
80-
<item>
81-
<attribute name="label" translatable="yes">Followers</attribute>
82-
<attribute name="action">view.source</attribute>
83-
<attribute name="target">followers</attribute>
84-
</item> -->
85-
86-
<!-- <section> -->
87-
<item>
88-
<attribute name="label" translatable="yes">Include Replies</attribute>
89-
<attribute name="action">view.include-replies</attribute>
90-
<attribute name="hidden-when">action-disabled</attribute>
91-
</item>
92-
<item>
93-
<attribute name="label" translatable="yes">Include Media</attribute>
94-
<attribute name="action">view.only-media</attribute>
95-
<attribute name="hidden-when">action-disabled</attribute>
96-
</item>
97-
<!-- </section> -->
98-
99-
</submenu>
100-
10168
<!-- <section> -->
10269
<!-- <submenu id="copy-menu">
10370
<attribute name="label" translatable="yes">Share</attribute>

src/Views/ContentBase.vala

+3-3
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,11 @@ public class Tuba.Views.ContentBase : Views.Base {
101101
this.model.remove_all ();
102102
}
103103

104-
protected virtual void clear_all_but_first () {
104+
protected virtual void clear_all_but_first (int i = 1) {
105105
base.clear ();
106106

107-
if (model.n_items > 1)
108-
model.splice (1, model.n_items - 1, {});
107+
if (model.n_items > i)
108+
model.splice (i, model.n_items - i, {});
109109
}
110110

111111
public override void on_content_changed () {

src/Views/Profile.vala

+36-26
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ public class Tuba.Views.Profile : Views.Accounts {
1616
}
1717
}
1818

19+
public class FilterGroup : Widgetizable, GLib.Object {
20+
public override Gtk.Widget to_widget () {
21+
return new Widgets.ProfileFilterGroup ();
22+
}
23+
}
24+
1925
public ProfileAccount profile { get; construct set; }
20-
public bool include_replies { get; set; default = false; }
21-
public bool only_media { get; set; default = false; }
26+
public Widgets.ProfileFilterGroup.Filter filter { get; set; default = Widgets.ProfileFilterGroup.Filter.POSTS; }
2227
public string source { get; set; default = "statuses"; }
2328

2429
protected Gtk.MenuButton menu_button;
25-
protected SimpleAction media_action;
26-
protected SimpleAction replies_action;
2730
protected SimpleAction muting_action;
2831
protected SimpleAction hiding_reblogs_action;
2932
protected SimpleAction blocking_action;
@@ -41,14 +44,15 @@ public class Tuba.Views.Profile : Views.Accounts {
4144
);
4245

4346
model.insert (0, profile);
47+
model.insert (1, new FilterGroup ());
4448
profile.rs.invalidated.connect (on_rs_updated);
4549
}
4650
~Profile () {
4751
debug ("Destroying Profile view");
4852
}
4953

5054
public bool append_pinned () {
51-
if (source == "statuses") {
55+
if (source == "statuses" && filter == Widgets.ProfileFilterGroup.Filter.POSTS) {
5256
new Request.GET (@"/api/v1/accounts/$(profile.account.id)/statuses")
5357
.with_account (account)
5458
.with_param ("pinned", "true")
@@ -64,8 +68,7 @@ public class Tuba.Views.Profile : Views.Accounts {
6468

6569
to_add += e_status;
6670
});
67-
model.splice (1, 0, to_add);
68-
71+
model.splice (2, 0, to_add);
6972
})
7073
.exec ();
7174
}
@@ -110,6 +113,12 @@ public class Tuba.Views.Profile : Views.Accounts {
110113
widget_status.pin_changed.connect (on_refresh);
111114
}
112115

116+
var widget_filter_group = widget as Widgets.ProfileFilterGroup;
117+
if (widget_filter_group != null) {
118+
widget_filter_group.remove_css_class ("card");
119+
widget_filter_group.filter_change.connect (change_filter);
120+
}
121+
113122
return widget;
114123
}
115124

@@ -151,6 +160,11 @@ public class Tuba.Views.Profile : Views.Accounts {
151160
invalidate_actions (true);
152161
}
153162

163+
protected void change_filter (Widgets.ProfileFilterGroup.Filter filter) {
164+
this.filter = filter;
165+
invalidate_actions (true);
166+
}
167+
154168
protected override void build_header () {
155169
base.build_header ();
156170

@@ -198,26 +212,12 @@ public class Tuba.Views.Profile : Views.Accounts {
198212
}
199213

200214
protected override void clear () {
201-
base.clear_all_but_first ();
215+
base.clear_all_but_first (2);
202216
}
203217

204218
protected override void build_actions () {
205219
base.build_actions ();
206220

207-
media_action = new SimpleAction.stateful ("only-media", null, false);
208-
media_action.change_state.connect (v => {
209-
media_action.set_state (only_media = v.get_boolean ());
210-
invalidate_actions (true);
211-
});
212-
actions.add_action (media_action);
213-
214-
replies_action = new SimpleAction.stateful ("include-replies", null, false);
215-
replies_action.change_state.connect (v => {
216-
replies_action.set_state (include_replies = v.get_boolean ());
217-
invalidate_actions (true);
218-
});
219-
actions.add_action (replies_action);
220-
221221
notify_on_new_post_action = new SimpleAction.stateful ("notify_on_post", null, false);
222222
notify_on_new_post_action.change_state.connect (v => {
223223
profile.rs.modify ("follow", {{"notify", v.get_boolean ().to_string ()}});
@@ -332,8 +332,6 @@ public class Tuba.Views.Profile : Views.Accounts {
332332
}
333333

334334
void invalidate_actions (bool refresh) {
335-
replies_action.set_enabled (accepts == typeof (API.Status));
336-
media_action.set_enabled (accepts == typeof (API.Status));
337335
muting_action.set_state (profile.rs.muting);
338336
hiding_reblogs_action.set_state (!profile.rs.showing_reblogs);
339337
hiding_reblogs_action.set_enabled (profile.rs.following);
@@ -356,8 +354,20 @@ public class Tuba.Views.Profile : Views.Accounts {
356354

357355
public override Request append_params (Request req) {
358356
if (page_next == null && source == "statuses") {
359-
req.with_param ("exclude_replies", (!include_replies).to_string ());
360-
req.with_param ("only_media", only_media.to_string ());
357+
switch (this.filter) {
358+
case Widgets.ProfileFilterGroup.Filter.POSTS:
359+
req.with_param ("exclude_replies", "true");
360+
break;
361+
case Widgets.ProfileFilterGroup.Filter.REPLIES:
362+
req.with_param ("exclude_replies", "false");
363+
req.with_param ("exclude_reblogs", "true");
364+
break;
365+
case Widgets.ProfileFilterGroup.Filter.MEDIA:
366+
req.with_param ("only_media", "true");
367+
break;
368+
default:
369+
assert_not_reached ();
370+
}
361371
}
362372
return base.append_params (req);
363373
}

src/Views/Timeline.vala

+2-2
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ public class Tuba.Views.Timeline : AccountHolder, Streamable, Views.ContentBase
151151
base.clear ();
152152
}
153153

154-
protected override void clear_all_but_first () {
154+
protected override void clear_all_but_first (int i = 1) {
155155
cleanup_timeline_api ();
156-
base.clear_all_but_first ();
156+
base.clear_all_but_first (i);
157157
}
158158

159159
public void get_pages (string? header) {

0 commit comments

Comments
 (0)