You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: sticker.rs
    path of file: ./repos/paper-plane/src/ui/session/content/message_row
    
    the code of the file until where you have to start completion: use adw::prelude::*;
use glib::once_cell::sync::Lazy;
use gtk::glib;
use gtk::subclass::prelude::*;
use gtk::CompositeTemplate;

use crate::model;
use crate::ui;
use crate::ui::MessageBaseExt;

const MAX_REPLY_CHAR_WIDTH: i32 = 18;

const STICKER_SIZE: i32 = 176;
const EMOJI_SIZE: i32 = 112;

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate)]
    #[template(resource = "/app/drey/paper-plane/ui/session/content/message_row/sticker.ui")]
    pub(crate) struct MessageSticker {
        pub(super) message: glib::WeakRef<model::Message>,
        #[template_child]
        pub(super) overlay: TemplateChild<gtk::Overlay>,
        #[template_child]
        pub(super) click: TemplateChild<gtk::GestureClick>,
        #[template_child]
        pub(super) sticker: TemplateChild<ui::Sticker>,
      
    
    fn set_message(&self, message: &Self::Message) {
        let imp = self.imp();

        if imp.message.upgrade().as_ref() == Some(message) {
            return;
        }

        imp.message.set(Some(message));

        imp.indicators.set_message(message.upcast_ref());

        if matches!(
            message.reply_to(),
            Some(model::BoxedMessageReplyTo(
                tdlib::enums::MessageReplyTo::Message(_)
            ))
        ) {
            let reply = ui::MessageReply::new(message);
            reply.set_valign(gtk::Align::Start);
            reply.set_max_char_width(MAX_REPLY_CHAR_WIDTH);

            // FIXME: Do not show message reply when message is being deleted
            // Sticker and the reply should be at the opposite sides of the box
            if message.is_outgoing() {
                reply.insert_before(self, Some(&imp.overlay.get()));
            } else {
                reply.insert_after(self, Some(&imp.overlay.get()));
            }
        }

        let (sticker, looped, is_emoji) = match message.content().0 {
            tdlib::enums::MessageContent::MessageSticker(data) => {
                let sticker = data.sticker;
                (sticker, true, false)
            }
            tdlib::enums::MessageContent::MessageAnimatedEmoji(data) => {
                let sticker = data.animated_emoji.sticker.unwrap();
                let looped = matches!(
                    sticker.full_type,
                    tdlib::enums::StickerFullType::CustomEmoji(_)
                );
                (sticker, looped, true)
            }
            _ => unreachable!(),
        };

        // TODO: that should be handled a bit better in the future
        match &sticker.full_type {
            tdlib::enums::StickerFullType::CustomEmoji(data) if data.needs_repainting => {
                self.add_css_class("needs-repainting")
            }
            _ => self.remove_css_class("needs-repainting"),
        }

        let (size, margin_bottom) = if is_emoji {
            (EMOJI_SIZE, 8)
        } else {
            (STICKER_SIZE, 0)
        };

        imp.sticker.set_longer_side_size(size);
        imp.sticker.set_margin_bottom(margin_bottom);

        imp.sticker
            .update_sticker(sticker, looped, message.chat_().session_());

        self.notify("message");
    }