Codebase list gnome-twitch / debian/0.4.1-1 src / gt-games-container-child.c
debian/0.4.1-1

Tree @debian/0.4.1-1 (Download .tar.gz)

gt-games-container-child.c @debian/0.4.1-1raw · history · blame

/*
 *  This file is part of GNOME Twitch - 'Enjoy Twitch on your GNU/Linux desktop'
 *  Copyright © 2017 Vincent Szolnoky <vinszent@vinszent.com>
 *
 *  GNOME Twitch is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  GNOME Twitch is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GNOME Twitch. If not, see <http://www.gnu.org/licenses/>.
 */

#include "gt-games-container-child.h"
#include "utils.h"
#include <glib/gi18n.h>
#include <glib/gprintf.h>

#define TAG "GtGamesContainerChild"
#include "gnome-twitch/gt-log.h"

typedef struct
{
    GtGame* game;

    GtkWidget* cover_stack;
    GtkWidget* cover_image;
    GtkWidget* cover_overlay_revealer;
    GtkWidget* name_label;
    GtkWidget* viewers_label;
    GtkWidget* viewers_image;
} GtGamesContainerChildPrivate;

G_DEFINE_TYPE_WITH_PRIVATE(GtGamesContainerChild, gt_games_container_child, GTK_TYPE_FLOW_BOX_CHILD)

enum
{
    PROP_0,
    PROP_GAME,
    NUM_PROPS
};

static GParamSpec* props[NUM_PROPS];

static void
update_viewers_cb(GObject* source,
    GParamSpec* pspec, gpointer udata)
{
    RETURN_IF_FAIL(GT_IS_GAMES_CONTAINER_CHILD(udata));
    RETURN_IF_FAIL(GT_IS_GAME(source));

    GtGamesContainerChild* self = GT_GAMES_CONTAINER_CHILD(udata);
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    gint64 viewers = gt_game_get_viewers(priv->game);
    gchar label[50];

    if (viewers > 1e4)
    {
        // Translators: Used for when viewers >= 1000
        // Shorthand for thousands. Ex (English): 6200 = 6.2k
        g_sprintf(label, _("%3.1fk"), (gdouble) viewers / 1e3);
    }
    else
    {
        gchar num[50];

        g_sprintf(num, "%" G_GINT64_FORMAT, viewers);

        // Translators: Used for when viewers < 1000
        g_sprintf(label, _("%s"), num);

    }

    gtk_label_set_text(GTK_LABEL(priv->viewers_label), label);

    gtk_widget_set_visible(priv->viewers_label, viewers > -1);
    gtk_widget_set_visible(priv->viewers_image, viewers > -1);
}

static void
motion_enter_cb(GtkWidget* widget,
    GdkEvent* evt, gpointer udata)
{
    GtGamesContainerChild* self = GT_GAMES_CONTAINER_CHILD(udata);
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    gtk_revealer_set_reveal_child(GTK_REVEALER(priv->cover_overlay_revealer), TRUE);
}

static void
motion_leave_cb(GtkWidget* widget,
    GdkEvent* evt, gpointer udata)
{
    GtGamesContainerChild* self = GT_GAMES_CONTAINER_CHILD(udata);
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    gtk_revealer_set_reveal_child(GTK_REVEALER(priv->cover_overlay_revealer), FALSE);
}

static void
updating_cb(GObject* source,
    GParamSpec* pspec, gpointer udata)
{
    g_assert(GT_IS_GAMES_CONTAINER_CHILD(udata));
    g_assert(GT_IS_GAME(source));

    GtGamesContainerChild* self = GT_GAMES_CONTAINER_CHILD(udata);
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);
    GtGame* game = GT_GAME(source);

    gtk_stack_set_visible_child_name(GTK_STACK(priv->cover_stack),
        gt_game_get_updating(game) ? "load-spinner" : "cover");
}

static void
finalize(GObject* object)
{
    GtGamesContainerChild* self = (GtGamesContainerChild*) object;
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    g_object_unref(priv->game);

    G_OBJECT_CLASS(gt_games_container_child_parent_class)->finalize(object);
}

static void
get_property (GObject*    obj,
              guint       prop,
              GValue*     val,
              GParamSpec* pspec)
{
    GtGamesContainerChild* self = GT_GAMES_CONTAINER_CHILD(obj);
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    switch (prop)
    {
        case PROP_GAME:
            g_value_set_object(val, priv->game);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec);
    }
}

static void
set_property(GObject* obj,
    guint prop, const GValue* val,
    GParamSpec* pspec)
{
    GtGamesContainerChild* self = GT_GAMES_CONTAINER_CHILD(obj);
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    switch (prop)
    {
        case PROP_GAME:
            g_clear_object(&priv->game);
            priv->game = utils_value_ref_sink_object(val);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec);
    }
}

static void
constructed(GObject* obj)
{
    GtGamesContainerChild* self = GT_GAMES_CONTAINER_CHILD(obj);
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    g_object_bind_property(priv->game, "name",
                           priv->name_label, "label",
                           G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
    g_object_bind_property(priv->game, "preview",
                           priv->cover_image, "pixbuf",
                           G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);

    g_signal_connect(priv->game, "notify::viewers", G_CALLBACK(update_viewers_cb), self);
    g_signal_connect_object(priv->game, "notify::updating", G_CALLBACK(updating_cb), self, 0);

    update_viewers_cb(G_OBJECT(priv->game), NULL, self);
    updating_cb(G_OBJECT(priv->game), NULL, self);

    G_OBJECT_CLASS(gt_games_container_child_parent_class)->constructed(obj);
}

static void
gt_games_container_child_class_init(GtGamesContainerChildClass* klass)
{
    GObjectClass* object_class = G_OBJECT_CLASS(klass);

    object_class->finalize = finalize;
    object_class->get_property = get_property;
    object_class->set_property = set_property;
    object_class->constructed = constructed;

    props[PROP_GAME] = g_param_spec_object("game",
                                           "Game",
                                           "Associated game",
                                           GT_TYPE_GAME,
                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);

    g_object_class_install_properties(object_class,
                                      NUM_PROPS,
                                      props);

    gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(klass),
                                                "/com/vinszent/GnomeTwitch/ui/gt-games-container-child.ui");
    gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(klass), motion_enter_cb);
    gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(klass), motion_leave_cb);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtGamesContainerChild, cover_image);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtGamesContainerChild, cover_overlay_revealer);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtGamesContainerChild, name_label);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtGamesContainerChild, cover_stack);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtGamesContainerChild, viewers_label);
    gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtGamesContainerChild, viewers_image);
}

static void
gt_games_container_child_init(GtGamesContainerChild* self)
{
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    gtk_widget_init_template(GTK_WIDGET(self));
}

GtGamesContainerChild*
gt_games_container_child_new(GtGame* game)
{
    return g_object_new(GT_TYPE_GAMES_VIEW_CHILD,
        "game", game, NULL);
}

void
gt_games_container_child_hide_overlay(GtGamesContainerChild* self)
{
    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    gtk_revealer_set_reveal_child(GTK_REVEALER(priv->cover_overlay_revealer), FALSE);
}


GtGame*
gt_games_container_child_get_game(GtGamesContainerChild* self)
{
    g_assert(GT_IS_GAMES_CONTAINER_CHILD(self));

    GtGamesContainerChildPrivate* priv = gt_games_container_child_get_instance_private(self);

    return priv->game;
}