Skip to content

Commit

Permalink
feat: scheduled posts (#1209)
Browse files Browse the repository at this point in the history
  • Loading branch information
GeopJr authored Nov 21, 2024
1 parent f017d03 commit 3ba391e
Show file tree
Hide file tree
Showing 20 changed files with 592 additions and 32 deletions.
2 changes: 2 additions & 0 deletions data/gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<file preprocess="xml-stripblanks">icons/scalable/actions/tuba-birthday-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/tuba-transparent-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/tuba-police-badge2-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/tuba-clock-alt-symbolic.svg</file>
<!-- <file preprocess="xml-stripblanks">icons/scalable/actions/tuba-language-symbolic.svg</file> -->

<file>gtk/help-overlay.ui</file>
Expand Down Expand Up @@ -110,6 +111,7 @@
<file>ui/dialogs/preferences.ui</file>
<file>ui/dialogs/profile_edit.ui</file>
<file>ui/dialogs/filter_edit.ui</file>
<file>ui/dialogs/schedule.ui</file>
<file>ui/menus.ui</file>
</gresource>
</gresources>
2 changes: 2 additions & 0 deletions data/icons/scalable/actions/tuba-clock-alt-symbolic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 0 additions & 7 deletions data/ui/dialogs/compose.ui
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@
<signal name="clicked" handler="on_exit" swapped="no" />
</object>
</child>
<child type="end">
<object class="GtkButton" id="commit_button">
<property name="label" translatable="yes">_Publish</property>
<property name="use-underline">1</property>
<signal name="clicked" handler="on_commit" swapped="no" />
</object>
</child>
</object>
</child>

Expand Down
147 changes: 147 additions & 0 deletions data/ui/dialogs/schedule.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0" />
<requires lib="libadwaita" version="1.0" />
<object class="GtkAdjustment" id="hour_adjustment">
<property name="lower">0</property>
<property name="upper">23</property>
<property name="step_increment">1</property>
<property name="page_increment">1</property>
</object>
<object class="GtkAdjustment" id="minutes_adjustment">
<property name="lower">0</property>
<property name="upper">59</property>
<property name="step_increment">1</property>
<property name="page_increment">1</property>
</object>
<object class="GtkAdjustment" id="seconds_adjustment">
<property name="lower">0</property>
<property name="upper">59</property>
<property name="step_increment">1</property>
<property name="page_increment">1</property>
</object>
<template class="TubaDialogsSchedule" parent="AdwDialog">
<property name="content_width">500</property>
<property name="content_height">600</property>
<property name="width_request">360</property>
<property name="height_request">200</property>
<!-- translators: window title -->
<property name="title" translatable="yes">Schedule Date and Time Picker</property>

<child>
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<property name="show_end_title_buttons">0</property>
<property name="show_start_title_buttons">0</property>

<child type="start">
<object class="GtkButton">
<property name="label" translatable="yes">Cancel</property>
<signal name="clicked" handler="on_exit" swapped="no" />
</object>
</child>
<child type="end">
<object class="GtkButton" id="schedule_button">
<!-- translators: Leave &amp; as is, it gets converted to & -->
<property name="label" translatable="yes">Schedule &amp; Publish</property>
<signal name="clicked" handler="on_schedule" swapped="no" />
<style>
<class name="suggested-action" />
</style>
</object>
</child>
</object>
</child>

<property name="content">
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="AdwClamp">
<property name="valign">start</property>
<property name="tightening-threshold">100</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="margin-top">6</property>
<property name="margin-bottom">24</property>
<property name="spacing">24</property>
<child>
<object class="AdwPreferencesGroup">
<!-- translators: Title used for calendar date picking -->
<property name="title" translatable="yes">Date</property>
<child>
<object class="GtkListBoxRow">
<property name="activatable">false</property>
<style>
<class name="card" />
</style>
<child>
<object class="GtkCalendar" id="calendar">
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="vexpand">1</property>
<property name="hexpand">1</property>
<signal name="day-selected" handler="validate" />
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<!-- translators: Title used for time picking -->
<property name="title" translatable="yes">Time</property>
<child>
<object class="AdwSpinRow" id="hours_spin_row">
<!-- translators: Label on an hour picker -->
<property name="title" translatable="yes">Hour</property>
<property name="text">0</property>
<property name="adjustment">hour_adjustment</property>
<property name="value">0</property>
<signal name="notify::value" handler="validate" />
</object>
</child>
<child>
<object class="AdwSpinRow" id="minutes_spin_row">
<!-- translators: Label on an minute picker -->
<property name="title" translatable="yes">Minute</property>
<property name="text">0</property>
<property name="adjustment">minutes_adjustment</property>
<property name="value">0</property>
<signal name="notify::value" handler="validate" />
</object>
</child>
<child>
<object class="AdwSpinRow" id="seconds_spin_row">
<!-- translators: Label on an second picker -->
<property name="title" translatable="yes">Second</property>
<property name="text">0</property>
<property name="adjustment">seconds_adjustment</property>
<property name="value">0</property>
<signal name="notify::value" handler="validate" />
</object>
</child>
<child>
<object class="AdwComboRow" id="timezone_combo_row">
<property name="title" translatable="yes">Timezone</property>
<signal name="notify::selected" handler="validate" />
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
</template>
</interface>
2 changes: 2 additions & 0 deletions src/API/Entity.vala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class Tuba.Entity : GLib.Object, Widgetizable, Json.Serializable {
return get_class ().find_property ("kind");
case "value":
return get_class ().find_property ("val");
case "params":
return get_class ().find_property ("props");
default:
return get_class ().find_property (name);
}
Expand Down
58 changes: 58 additions & 0 deletions src/API/ScheduledStatus.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
public class Tuba.API.ScheduledStatus : Entity, Widgetizable {
// NOTE: Don't forget to update in the year 3000
public const int DRAFT_YEAR = 2000 + 3000;

public class Params : Entity {
public class Poll : Entity {
public Gee.ArrayList<string> options { get; set; default=new Gee.ArrayList <string> (); }
public int64 expires_in { get; set; default=0; }
public bool multiple { get; set; default=false; }
public bool hide_totals { get; set; default=false; }

public override Type deserialize_array_type (string prop) {
switch (prop) {
case "options":
return Type.STRING;
}

return base.deserialize_array_type (prop);
}
}

public string text { get; set; }
public Poll? poll { get; set; }
public Gee.ArrayList<string>? media_ids { get; set; }
public bool sensitive { get; set; default=false; }
public string? spoiler_text { get; set; }
public string visibility { get; set; }
public string? language { get; set; }
public string? in_reply_to_id { get; set; }

public override Type deserialize_array_type (string prop) {
switch (prop) {
case "media-ids":
return Type.STRING;
}

return base.deserialize_array_type (prop);
}
}

public string id { get; set; }
public string scheduled_at { get; set; }
public Gee.ArrayList<API.Attachment>? media_attachments { get; set; default = null; }
public Params? props { get; set; }

public override Type deserialize_array_type (string prop) {
switch (prop) {
case "media-attachments":
return typeof (API.Attachment);
}

return base.deserialize_array_type (prop);
}

public override Gtk.Widget to_widget () {
return new Widgets.ScheduledStatus (this);
}
}
1 change: 1 addition & 0 deletions src/API/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sources += files(
'Poll.vala',
'PollOption.vala',
'Relationship.vala',
'ScheduledStatus.vala',
'SearchResult.vala',
'SearchResults.vala',
'Status.vala',
Expand Down
6 changes: 6 additions & 0 deletions src/Application.vala
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ namespace Tuba {
{ "open-announcements", open_announcements },
{ "open-follow-requests", open_follow_requests },
{ "open-mutes-blocks", open_mutes_blocks },
{ "open-scheduled-posts", open_scheduled_posts },
{ "open-admin-dashboard", open_admin_dashboard }
};

Expand Down Expand Up @@ -530,6 +531,11 @@ namespace Tuba {
close_sidebar ();
}

public void open_scheduled_posts () {
main_window.open_view (new Views.ScheduledStatuses ());
close_sidebar ();
}

public void open_admin_dashboard () {
new Dialogs.Admin.Window ().present ();
}
Expand Down
65 changes: 60 additions & 5 deletions src/Dialogs/Composer/Dialog.vala
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,43 @@ public class Tuba.Dialogs.Compose : Adw.Dialog {
public delegate void SuccessCallback (API.Status cb_status);
protected SuccessCallback? cb;

Gtk.Widget commit_button;
private bool _commit_button_has_menu = false;
public bool commit_button_has_menu {
get { return _commit_button_has_menu; }
construct {
_commit_button_has_menu = value;

if (value) {
var menu_model = new GLib.Menu ();
menu_model.append (_("Schedule Post"), "composer.schedule");

commit_button = new Adw.SplitButton () {
label = _("_Publish"),
use_underline = true,
menu_model = menu_model
};
((Adw.SplitButton) commit_button).clicked.connect (on_commit);
} else {
commit_button = new Gtk.Button () {
label = _("_Publish"),
use_underline = true
};
((Gtk.Button) commit_button).clicked.connect (on_commit);
}

header.pack_end (commit_button);
}
}

public string button_label {
set { commit_button.label = value; }
set {
if (_commit_button_has_menu) {
((Adw.SplitButton) commit_button).label = value;
} else {
((Gtk.Button) commit_button).label = value;
}
}
}

public string button_class {
Expand All @@ -159,8 +194,12 @@ public class Tuba.Dialogs.Compose : Adw.Dialog {
var paste_action = new SimpleAction ("paste", null);
paste_action.activate.connect (emit_paste_signal);

var schedule_action = new SimpleAction ("schedule", null);
schedule_action.activate.connect (on_schedule_action_activated);

var action_group = new GLib.SimpleActionGroup ();
action_group.add_action (paste_action);
action_group.add_action (schedule_action);

this.insert_action_group ("composer", action_group);
add_binding_action (Gdk.Key.V, Gdk.ModifierType.CONTROL_MASK, "composer.paste", null);
Expand Down Expand Up @@ -269,16 +308,15 @@ public class Tuba.Dialogs.Compose : Adw.Dialog {
}

[GtkChild] unowned Adw.ViewSwitcher title_switcher;
[GtkChild] unowned Gtk.Button commit_button;

[GtkChild] unowned Adw.ViewStack stack;
[GtkChild] unowned Adw.HeaderBar header;

public string? quote_id { get; set; }
public Compose (API.Status template = new API.Status.empty (), bool t_force_cursor_at_start = false, string? quote_id = null) {
Object (
commit_button_has_menu: true,
status: new BasicStatus.from_status (template),
original_status: new BasicStatus.from_status (template),
button_label: _("_Publish"),
button_class: "suggested-action",
force_cursor_at_start: t_force_cursor_at_start,
quote_id: quote_id
Expand Down Expand Up @@ -384,7 +422,7 @@ public class Tuba.Dialogs.Compose : Adw.Dialog {
}
}

[GtkCallback] void on_commit () {
void on_commit () {
this.sensitive = false;
transaction.begin ((obj, res) => {
try {
Expand Down Expand Up @@ -432,6 +470,7 @@ public class Tuba.Dialogs.Compose : Adw.Dialog {
builder.end_array ();
}

private string? schedule_iso8601 = null;
private Json.Builder populate_json_body () {
var builder = new Json.Builder ();
builder.begin_object ();
Expand All @@ -442,6 +481,10 @@ public class Tuba.Dialogs.Compose : Adw.Dialog {
builder.set_member_name ("quote_id");
builder.add_string_value (quote_id);
}
if (schedule_iso8601 != null) {
builder.set_member_name ("scheduled_at");
builder.add_string_value (schedule_iso8601);
}

builder.end_object ();
return builder;
Expand Down Expand Up @@ -472,4 +515,16 @@ public class Tuba.Dialogs.Compose : Adw.Dialog {
on_close ();
}

private void on_schedule_action_activated () {
if (!commit_button.sensitive) return;

var schedule_dlg = new Dialogs.Schedule ();
schedule_dlg.schedule_picked.connect (on_schedule_picked);
schedule_dlg.present (this);
}

private void on_schedule_picked (string iso8601) {
schedule_iso8601 = iso8601;
on_commit ();
}
}
Loading

0 comments on commit 3ba391e

Please sign in to comment.