Update user avatar on login
This commit is contained in:
parent
30f8348286
commit
ba20c1a287
|
@ -1,13 +1,27 @@
|
|||
public class Tootle.Account{
|
||||
|
||||
public int id = -1;
|
||||
public int64 id;
|
||||
public string username;
|
||||
public string username_acct;
|
||||
public string acct;
|
||||
public string display_name;
|
||||
public string note;
|
||||
public string avatar;
|
||||
|
||||
public Account(){
|
||||
public Account(int64 id){
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static Account parse(Json.Object obj) {
|
||||
var id = int64.parse (obj.get_string_member ("id"));
|
||||
var account = new Account (id);
|
||||
|
||||
account.username = obj.get_string_member ("username");
|
||||
account.acct = obj.get_string_member ("acct");
|
||||
account.display_name = obj.get_string_member ("display_name");
|
||||
account.note = obj.get_string_member ("note");
|
||||
account.avatar = obj.get_string_member ("avatar");
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
public class Tootle.Account{
|
||||
|
||||
public int id = -1;
|
||||
public string username;
|
||||
public string username_acct;
|
||||
public string display_name;
|
||||
public string note;
|
||||
|
||||
public Account(){
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,11 @@ using GLib;
|
|||
|
||||
public class Tootle.AccountManager : Object{
|
||||
|
||||
public abstract signal void changed_current(Account account);
|
||||
public abstract signal void added(Account account);
|
||||
public abstract signal void removed(Account account);
|
||||
|
||||
private static Account current;
|
||||
private static Settings settings;
|
||||
private static AccountManager _instance;
|
||||
public static AccountManager instance{
|
||||
|
@ -93,5 +98,21 @@ public class Tootle.AccountManager : Object{
|
|||
});
|
||||
return msg;
|
||||
}
|
||||
|
||||
public Soup.Message update_current (){
|
||||
var msg = new Soup.Message("GET", settings.instance_url + "/api/v1/accounts/verify_credentials");
|
||||
NetManager.instance.queue(msg, (sess, mess) => {
|
||||
try{
|
||||
var root = NetManager.parse (mess);
|
||||
current = Account.parse(root);
|
||||
changed_current (current);
|
||||
}
|
||||
catch (GLib.Error e) {
|
||||
warning ("Can't get current user");
|
||||
warning (e.message);
|
||||
}
|
||||
});
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
using GLib;
|
||||
|
||||
public class Tootle.AccountManager : Object{
|
||||
|
||||
private static Settings settings;
|
||||
private static AccountManager _instance;
|
||||
public static AccountManager instance{
|
||||
get{
|
||||
if(_instance == null)
|
||||
_instance = new AccountManager();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
construct{
|
||||
settings = Settings.instance;
|
||||
}
|
||||
|
||||
public AccountManager(){
|
||||
Object();
|
||||
}
|
||||
|
||||
public bool has_client_tokens(){
|
||||
var client_id = settings.client_id;
|
||||
var client_secret = settings.client_secret;
|
||||
|
||||
return !(client_id == "null" || client_secret == "null");
|
||||
}
|
||||
|
||||
public bool has_access_token (){
|
||||
return settings.access_token != "null";
|
||||
}
|
||||
|
||||
public void request_auth_code (string client_id){
|
||||
var pars = "?scope=read%20write%20follow";
|
||||
pars += "&response_type=code";
|
||||
pars += "&redirect_uri=urn:ietf:wg:oauth:2.0:oob";
|
||||
pars += "&client_id=" +client_id;
|
||||
|
||||
try {
|
||||
AppInfo.launch_default_for_uri (settings.instance_url + "/oauth/authorize" + pars, null);
|
||||
}
|
||||
catch (GLib.Error e){
|
||||
warning (e.message);
|
||||
}
|
||||
}
|
||||
|
||||
public Soup.Message request_client_tokens(){
|
||||
var pars = "?client_name=Tootle";
|
||||
pars += "&redirect_uris=urn:ietf:wg:oauth:2.0:oob";
|
||||
pars += "&scopes=read%20write%20follow";
|
||||
|
||||
var msg = new Soup.Message("POST", settings.instance_url + "/api/v1/apps" + pars);
|
||||
NetManager.instance.queue(msg, (sess, mess) => {
|
||||
try{
|
||||
var root = NetManager.parse (mess);
|
||||
var client_id = root.get_string_member ("client_id");
|
||||
var client_secret = root.get_string_member ("client_secret");
|
||||
settings.client_id = client_id;
|
||||
settings.client_secret = client_secret;
|
||||
debug ("Received tokens");
|
||||
|
||||
request_auth_code (client_id);
|
||||
}
|
||||
catch (GLib.Error e) {
|
||||
warning ("Can't request client secret.");
|
||||
warning (e.message);
|
||||
}
|
||||
});
|
||||
return msg;
|
||||
}
|
||||
|
||||
public Soup.Message try_auth (string code){
|
||||
var pars = "?client_id=" + settings.client_id;
|
||||
pars += "&client_secret=" + settings.client_secret;
|
||||
pars += "&redirect_uri=urn:ietf:wg:oauth:2.0:oob";
|
||||
pars += "&grant_type=authorization_code";
|
||||
pars += "&code=" + code;
|
||||
|
||||
var msg = new Soup.Message("POST", settings.instance_url + "/oauth/token" + pars);
|
||||
NetManager.instance.queue(msg, (sess, mess) => {
|
||||
try{
|
||||
var root = NetManager.parse (mess);
|
||||
var access_token = root.get_string_member ("access_token");
|
||||
settings.access_token = access_token;
|
||||
debug ("Got access token");
|
||||
Tootle.app.state_updated ();
|
||||
}
|
||||
catch (GLib.Error e) {
|
||||
warning ("Can't get access token");
|
||||
warning (e.message);
|
||||
}
|
||||
});
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
|
@ -22,12 +22,13 @@ public class Tootle.CacheManager : GLib.Object{
|
|||
Object ();
|
||||
}
|
||||
|
||||
public void load_image (string url, Granite.Widgets.Avatar avatar){
|
||||
//TODO: actually cache images
|
||||
public void load_avatar (string url, Granite.Widgets.Avatar avatar, int size = 32){
|
||||
var msg = new Soup.Message("GET", url);
|
||||
msg.finished.connect(()=>{
|
||||
uint8[] buf = msg.response_body.data;
|
||||
var loader = new PixbufLoader();
|
||||
loader.set_size (32,32);
|
||||
loader.set_size (size, size);
|
||||
loader.write(buf);
|
||||
loader.close();
|
||||
var pixbuf = loader.get_pixbuf ();
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
using Gdk;
|
||||
using GLib;
|
||||
|
||||
public class Tootle.CacheManager : GLib.Object{
|
||||
|
||||
private static CacheManager _instance;
|
||||
public static CacheManager instance{
|
||||
get{
|
||||
if(_instance == null)
|
||||
_instance = new CacheManager();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static string path_images;
|
||||
|
||||
construct{
|
||||
path_images = GLib.Environment.get_user_special_dir (UserDirectory.DOWNLOAD);
|
||||
}
|
||||
|
||||
public CacheManager(){
|
||||
Object ();
|
||||
}
|
||||
|
||||
//TODO: actually cache images
|
||||
public void load_image (string url, Granite.Widgets.Avatar avatar){
|
||||
var msg = new Soup.Message("GET", url);
|
||||
msg.finished.connect(()=>{
|
||||
uint8[] buf = msg.response_body.data;
|
||||
var loader = new PixbufLoader();
|
||||
loader.set_size (32,32);
|
||||
loader.write(buf);
|
||||
loader.close();
|
||||
var pixbuf = loader.get_pixbuf ();
|
||||
|
||||
avatar.pixbuf = pixbuf;
|
||||
});
|
||||
NetManager.instance.queue(msg, (sess, mess) => {});
|
||||
}
|
||||
|
||||
}
|
|
@ -83,6 +83,8 @@ public class Tootle.MainWindow: Gtk.Window {
|
|||
show_setup_views ();
|
||||
else
|
||||
show_main_views ();
|
||||
|
||||
AccountManager.instance.update_current ();
|
||||
}
|
||||
|
||||
private void show_setup_views (){
|
||||
|
|
|
@ -46,7 +46,7 @@ public class Tootle.NetManager : GLib.Object{
|
|||
|
||||
public static Json.Object parse(Soup.Message msg) throws GLib.Error{
|
||||
// stdout.printf ("Status Code: %u\n", msg.status_code);
|
||||
// stdout.printf ("Message length: %lld\n", msg.response_body.length);
|
||||
// stdout.printf ("Message length: %lld\n", msg.response_body.length);
|
||||
// stdout.printf ("Data: \n%s\n", (string) msg.response_body.data);
|
||||
|
||||
var parser = new Json.Parser ();
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
using Soup;
|
||||
using GLib;
|
||||
using Json;
|
||||
|
||||
public class Tootle.NetManager : GLib.Object{
|
||||
|
||||
public abstract signal void started();
|
||||
public abstract signal void finished();
|
||||
|
||||
private static NetManager _instance;
|
||||
public static NetManager instance{
|
||||
get{
|
||||
if(_instance == null)
|
||||
_instance = new NetManager();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private int requests_processing = 0;
|
||||
private Soup.Session session;
|
||||
|
||||
construct{
|
||||
session = new Soup.Session ();
|
||||
session.request_unqueued.connect (() => {
|
||||
requests_processing--;
|
||||
if(requests_processing <= 0)
|
||||
finished ();
|
||||
});
|
||||
}
|
||||
|
||||
public NetManager(){
|
||||
GLib.Object();
|
||||
}
|
||||
|
||||
public Soup.Message queue(Soup.Message msg, Soup.SessionCallback cb){
|
||||
requests_processing++;
|
||||
started ();
|
||||
|
||||
var token = Settings.instance.access_token;
|
||||
if(token != "null")
|
||||
msg.request_headers.append ("Authorization", "Bearer " + token);
|
||||
|
||||
session.queue_message (msg, cb);
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static Json.Object parse(Soup.Message msg) throws GLib.Error{
|
||||
stdout.printf ("Status Code: %u\n", msg.status_code);
|
||||
stdout.printf ("Message length: %lld\n", msg.response_body.length);
|
||||
stdout.printf ("Data: \n%s\n", (string) msg.response_body.data);
|
||||
|
||||
var parser = new Json.Parser ();
|
||||
parser.load_from_data ((string) msg.response_body.flatten ().data, -1);
|
||||
return parser.get_root ().get_object ();
|
||||
}
|
||||
|
||||
public static Json.Array parse_array(Soup.Message msg) throws GLib.Error{
|
||||
// stdout.printf ("Status Code: %u\n", msg.status_code);
|
||||
// stdout.printf ("Message length: %lld\n", msg.response_body.length);
|
||||
// stdout.printf ("Data: \n%s\n", (string) msg.response_body.data);
|
||||
|
||||
var parser = new Json.Parser ();
|
||||
parser.load_from_data ((string) msg.response_body.flatten ().data, -1);
|
||||
return parser.get_root ().get_array ();
|
||||
}
|
||||
|
||||
}
|
|
@ -26,9 +26,9 @@ public class Tootle.HomeView : Tootle.AbstractView {
|
|||
base (true);
|
||||
this.timeline = timeline;
|
||||
this.pars = pars;
|
||||
request_update ();
|
||||
|
||||
show_all();
|
||||
request_update ();
|
||||
|
||||
// var s = new Status(1);
|
||||
// s.content = "Test content, wow!";
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
using Gtk;
|
||||
using Gdk;
|
||||
|
||||
public class Tootle.HomeView : Tootle.AbstractView {
|
||||
|
||||
Gtk.Box view;
|
||||
Gtk.ScrolledWindow scroll;
|
||||
|
||||
private string timeline;
|
||||
private string pars;
|
||||
|
||||
construct {
|
||||
view = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
|
||||
view.hexpand = true;
|
||||
view.valign = Gtk.Align.START;
|
||||
|
||||
scroll = new Gtk.ScrolledWindow (null, null);
|
||||
scroll.hexpand = true;
|
||||
scroll.vexpand = true;
|
||||
scroll.hscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
scroll.add (view);
|
||||
add (scroll);
|
||||
}
|
||||
|
||||
public HomeView (string timeline = "home", string pars = "") {
|
||||
base (true);
|
||||
this.timeline = timeline;
|
||||
this.pars = pars;
|
||||
request_update ();
|
||||
|
||||
show_all();
|
||||
|
||||
// var s = new Status(1);
|
||||
// s.content = "Test content, wow!";
|
||||
// prepend (s);
|
||||
}
|
||||
|
||||
public override string get_icon () {
|
||||
return "user-home-symbolic";
|
||||
}
|
||||
|
||||
public override string get_name () {
|
||||
return "Home Timeline";
|
||||
}
|
||||
|
||||
public void prepend(Status status){
|
||||
var widget = new StatusWidget();
|
||||
widget.rebind (status);
|
||||
view.pack_end (widget, false, false, 0);
|
||||
}
|
||||
|
||||
public virtual Soup.Message request_update (){
|
||||
var url = Settings.instance.instance_url;
|
||||
url += "api/v1/timelines/";
|
||||
url += this.timeline;
|
||||
url += this.pars;
|
||||
|
||||
var msg = new Soup.Message("GET", url);
|
||||
NetManager.instance.queue(msg, (sess, mess) => {
|
||||
try{
|
||||
NetManager.parse_array (mess).foreach_element ((array, i, node) => {
|
||||
var object = node.get_object ();
|
||||
if (object != null){
|
||||
var status = Status.parse(object);
|
||||
prepend (status);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (GLib.Error e) {
|
||||
warning ("Can't update feed");
|
||||
warning (e.message);
|
||||
}
|
||||
});
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,9 +7,7 @@ public class Tootle.AccountsButton : Gtk.MenuButton{
|
|||
Gtk.Popover menu;
|
||||
|
||||
construct{
|
||||
//var iconfile = "/var/lib/AccountsService/icons/blue";
|
||||
avatar = new Granite.Widgets.Avatar.with_default_icon (24);
|
||||
avatar.set_tooltip_text (_("Account Options"));
|
||||
avatar.button_press_event.connect(event => {
|
||||
return false;
|
||||
});
|
||||
|
@ -35,6 +33,10 @@ public class Tootle.AccountsButton : Gtk.MenuButton{
|
|||
popover = menu;
|
||||
add(avatar);
|
||||
show_all ();
|
||||
|
||||
AccountManager.instance.changed_current.connect (account => {
|
||||
CacheManager.instance.load_avatar (account.avatar, avatar, 24);
|
||||
});
|
||||
}
|
||||
|
||||
public AccountsButton(){
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
using Gtk;
|
||||
|
||||
public class Tootle.AccountsButton : Gtk.MenuButton{
|
||||
|
||||
Granite.Widgets.Avatar avatar;
|
||||
Gtk.Grid grid;
|
||||
Gtk.Popover menu;
|
||||
|
||||
construct{
|
||||
avatar = new Granite.Widgets.Avatar.with_default_icon (24);
|
||||
avatar.set_tooltip_text (_("Account Options"));
|
||||
avatar.button_press_event.connect(event => {
|
||||
return false;
|
||||
});
|
||||
|
||||
var item_separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL);
|
||||
item_separator.hexpand = true;
|
||||
item_separator.margin_top = 6;
|
||||
|
||||
var item_settings = new Gtk.ModelButton ();
|
||||
item_settings.text = _("Settings");
|
||||
|
||||
grid = new Gtk.Grid ();
|
||||
grid.orientation = Gtk.Orientation.VERTICAL;
|
||||
grid.width_request = 200;
|
||||
grid.attach(item_separator, 0, 1, 1, 1);
|
||||
grid.attach(item_settings, 0, 2, 1, 1);
|
||||
grid.show_all ();
|
||||
|
||||
menu = new Gtk.Popover (null);
|
||||
menu.add (grid);
|
||||
|
||||
get_style_context ().add_class ("button_avatar");
|
||||
popover = menu;
|
||||
add(avatar);
|
||||
show_all ();
|
||||
}
|
||||
|
||||
public AccountsButton(){
|
||||
Object();
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,7 @@ public class Tootle.StatusWidget : Gtk.Grid {
|
|||
|
||||
construct {
|
||||
margin = 6;
|
||||
|
||||
avatar = new Granite.Widgets.Avatar.with_default_icon (32);
|
||||
avatar.valign = Gtk.Align.START;
|
||||
avatar.margin_end = 6;
|
||||
|
@ -32,7 +33,7 @@ public class Tootle.StatusWidget : Gtk.Grid {
|
|||
|
||||
reblogs = new Gtk.Label ("0");
|
||||
favorites = new Gtk.Label ("0");
|
||||
counters = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
|
||||
counters = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6); //TODO: currently useless
|
||||
counters.margin_top = 6;
|
||||
counters.margin_bottom = 12;
|
||||
counters.add(new Gtk.Image.from_icon_name ("media-playlist-repeat-symbolic", Gtk.IconSize.SMALL_TOOLBAR));
|
||||
|
@ -45,7 +46,7 @@ public class Tootle.StatusWidget : Gtk.Grid {
|
|||
attach(user, 1, 1, 1, 1);
|
||||
attach(content, 1, 2, 1, 1);
|
||||
attach(counters, 1, 3, 1, 1);
|
||||
show_all();
|
||||
show_all(); //TODO: display conversations
|
||||
}
|
||||
|
||||
public StatusWidget () {
|
||||
|
@ -59,7 +60,7 @@ public class Tootle.StatusWidget : Gtk.Grid {
|
|||
reblogs.label = status.reblogs_count.to_string ();
|
||||
favorites.label = status.favourites_count.to_string ();
|
||||
|
||||
CacheManager.instance.load_image (status.avatar, this.avatar);
|
||||
CacheManager.instance.load_avatar (status.avatar, this.avatar);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue