Browse Source

Добавлена боковая панель просмотра деталей видео

Вадим Королёв 1 year ago
parent
commit
ae02f4d5c8

+ 8 - 1
lib/YoutubeApi/youtubeapi.cpp

@@ -127,7 +127,14 @@ namespace ytapi {
     void downloadMediumThumnail(std::string yt_id, std::string save_path)
     {
         // Формирование URL
-        std::string url = "https://img.youtube.com/vi/" + yt_id + "/default.jpg";
+        std::string url = "https://img.youtube.com/vi/" + yt_id + "/mqdefault.jpg";
+        performCurlDownload(url, save_path);
+    }
+    
+    void downloadLargeThumnail(std::string yt_id, std::string save_path)
+    {
+        // Формирование URL
+        std::string url = "https://img.youtube.com/vi/" + yt_id + "/maxresdefault.jpg";
         performCurlDownload(url, save_path);
     }
 }

+ 3 - 0
lib/YoutubeApi/youtubeapi.hpp

@@ -60,4 +60,7 @@ namespace ytapi {
 
     // Скачивает превью видео и сохраняет в путь save_path
     void downloadMediumThumnail(std::string yt_id, std::string save_path);
+
+    // Скачивает большое превью видео и сохраняет в путь save_path
+    void downloadLargeThumnail(std::string yt_id, std::string save_path);
 }

+ 185 - 90
src/YTMPV/MainWindow.cpp

@@ -1,72 +1,84 @@
 #include "MainWindow.hpp"
 #include "core.hpp"
-#include <YoutubeApi/youtubeapi.hpp>
 #include <unistd.h>
+#include <gtkmm/signallistitemfactory.h>
+#include <glibmm/ustring.h>
+#include <Database/entities.hpp>
+#include <vector>
+#include <string>
+#include <YoutubeApi/youtubeapi.hpp>
+#include <gdkmm/texture.h>
+#include <gtkmm/picture.h>
+#include <gtkmm/label.h>
+#include <gdkmm/pixbuf.h>
+#include <glibmm/fileutils.h>
 
 namespace components {
     
     MainWindow::MainWindow()
-    : m_layout(Gtk::Orientation::VERTICAL)
-    , m_search_box(Gtk::Orientation::HORIZONTAL)
-    , m_search_field()
-    , m_search_btn()
-    , m_body(Gtk::Orientation::VERTICAL)
+        : Gtk::ApplicationWindow()
+        , m_layout(Gtk::Orientation::VERTICAL)
+        , m_stack()
+        , m_stackswitcher()
+
+        , m_search_layout(Gtk::Orientation::VERTICAL)
+        , m_search_head(Gtk::Orientation::HORIZONTAL)
+        , m_search_body(Gtk::Orientation::HORIZONTAL)
+        , m_search_entry()
+        , m_search_button()
+        , m_search_scroller()
+        , m_search_video_list()
     {
-        set_title("GTKYT");
+        set_title("YTMPV");
         set_default_size(800, 600);
         set_icon_name("youtube");
 
-        // Searchbar
-        m_search_btn.set_child(*(this->getButtonContents("Поиск", "find")));
-        m_search_btn.signal_clicked().connect(sigc::mem_fun(
-            *this,
-            &MainWindow::onSearchButtonClicked
-        ));
-        m_search_field.set_hexpand(true);
-        m_search_field.set_placeholder_text("Поиск YouTube");
-        m_search_box.append(m_search_field);
-        m_search_box.append(m_search_btn);
-        m_search_box.set_margin(8);
-
-        // --Body-
-        // Модель видео
-        m_video_storage = Gio::ListStore<VideoModel>::create();
-
-        // Модель выбора
+        // Создание модели выбора видео в поиске
+        m_video_storage = Gio::ListStore<components::VideoModel>::create();
         selection_model = Gtk::SingleSelection::create(m_video_storage);
         selection_model->set_autoselect(false);
         selection_model->set_can_unselect(true);
         selection_model->property_selected().signal_changed().connect(
             sigc::mem_fun(*this, &MainWindow::onVideoChanged));
-        m_video_list.set_model(selection_model);
+        m_search_video_list.set_model(selection_model);
 
-        // Создание фабрики
+        // Создание фабрики производства элементов списка видео
         auto factory = Gtk::SignalListItemFactory::create();
         factory->signal_setup().connect(
             sigc::mem_fun(*this, &MainWindow::onVideoSetup));
         factory->signal_bind().connect(
             sigc::mem_fun(*this, &MainWindow::onVideoBind));
-        m_video_list.set_factory(factory);
-        m_video_list.signal_activate().connect(
-            sigc::mem_fun(*this, &MainWindow::onVideoSelected));
+        m_search_video_list.set_factory(factory);
 
-        // Прокручиваемое окно
-        m_video_scroll.set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC);
-        m_video_scroll.set_expand(true);
-        m_video_scroll.set_child(m_video_list);
+        // SearchView head
+        m_search_button.set_child(*(core::getButtonContents("Поиск", "find")));
+        m_search_button.signal_clicked().connect(
+            sigc::mem_fun(*this, &MainWindow::onSearchButtonClicked));
+        m_search_entry.set_hexpand(true);
+        m_search_entry.set_placeholder_text("Введите запрос");
+        m_search_head.append(m_search_entry);
+        m_search_head.append(m_search_button);
+        m_search_head.set_margin(8);
+        m_search_layout.append(m_search_head);
 
-        m_body.append(m_video_scroll);
+        // SearchView body
+        m_search_scroller.set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC);
+        m_search_scroller.set_expand(true);
+        m_search_scroller.set_child(m_search_video_list);
+        m_search_body.set_end_child(m_search_scroller);
+        // TODO брать из настроек
+        m_search_body.set_position(256);
+        m_search_layout.append(m_search_body);
 
-        // Layout
-        m_layout.set_homogeneous(false);
-        m_layout.append(m_search_box);
-        m_layout.append(m_body);
-        
-        set_child(m_layout);
-    }
+        // WelcomeView
+        // TODO
 
-    MainWindow::~MainWindow()
-    {
+        m_stack.add(m_search_layout, "search", "Поиск видео");
+        m_stackswitcher.set_stack(m_stack);
+
+        m_layout.append(m_stackswitcher);
+        m_layout.append(m_stack);
+        set_child(m_layout);
     }
 
     void MainWindow::onSearchButtonClicked()
@@ -75,15 +87,17 @@ namespace components {
         m_video_storage->remove_all();
         
         // Получить результаты поиска
-        Glib::ustring query = m_search_field.get_buffer()->get_text();
+        Glib::ustring query = m_search_entry.get_buffer()->get_text();
         db::video found;
         std::vector<std::string> video_ids = ytapi::getVideoIDsByQuery(query.release());
 
         // Добавить в список видео
         for (auto id : video_ids) {
             found = core::getVideoByYTID(id);
-            m_video_storage->append(VideoModel::create(found.id, found.yt_id, found.title));
+            m_video_storage->append(components::VideoModel::create(found));
         }
+
+        searchSidebarRegularMode();
     }
 
     void MainWindow::onVideoSetup(const Glib::RefPtr<Gtk::ListItem>& list_item)
@@ -96,16 +110,71 @@ namespace components {
         list_item->set_child(*box_main);
     }
 
+    void MainWindow::onVideoBind(const Glib::RefPtr<Gtk::ListItem>& list_item)
+    {
+        auto pos = list_item->get_position();
+        if (pos == GTK_INVALID_LIST_POSITION) return;
+        auto item = m_video_storage->get_item(pos);
+        auto obj = item->m_obj;
+        
+        auto box_main = dynamic_cast<Gtk::Box*>(list_item->get_child());
+        if (!box_main) return;
+
+        auto thumbnail = dynamic_cast<Gtk::Picture*>(box_main->get_first_child());
+        if (!thumbnail) return;
+
+        auto lbl_title = dynamic_cast<Gtk::Label*>(thumbnail->get_next_sibling());
+        if (!lbl_title) return;
+
+        // Загрузка изображения превью видео с диска
+        std::string thumbnail_path = "thumbnails/default/" + obj.yt_id + ".jpg";
+        Glib::RefPtr<Gdk::Pixbuf> thumbnail_pixbuf;
+        try {
+            thumbnail_pixbuf = Gdk::Pixbuf::create_from_file(thumbnail_path, 120, 90);
+        } catch (Glib::FileError& e) {
+            switch (e.code()) {
+                case Glib::FileError::Code::NO_SUCH_ENTITY:
+                    // Превью на диске не найдено. Скачиваем...
+                    ytapi::downloadMediumThumnail(obj.yt_id, thumbnail_path);
+                    // ...и присваиваем
+                    thumbnail_pixbuf = Gdk::Pixbuf::create_from_file(thumbnail_path, 120, 90);
+                    break;
+
+                default:
+                    std::cout << "Unhandled error when creating thumbnail. Code is: " << e.code(); 
+                    break;
+            }
+        }
+        auto thumbnail_texture = Gdk::Texture::create_for_pixbuf(thumbnail_pixbuf);
+        thumbnail->set_paintable(thumbnail_texture);
+        thumbnail->set_can_shrink(false);
+        thumbnail->set_content_fit(Gtk::ContentFit::COVER);
+
+        lbl_title->set_text(obj.title);
+    }
+
     void MainWindow::onVideoChanged()
     {
         auto position = selection_model->get_selected();
         auto item = m_video_storage->get_item(position);
         if (!item) return;
+        auto obj = item->m_obj;
 
+        searchSidebarVideoDetailsMode(
+            obj.title,
+            obj.author_obj.name,
+            obj.description,
+            obj.published_at,
+            obj.yt_id
+        );
+    }
+
+    void MainWindow::playSingleVideo(std::string yt_id)
+    {
         // Запуск mpv в заднем фоне
         int pid = fork();
         if (pid == 0) {
-            std::string yt_url = "https://youtu.be/"+item->m_yt_id;
+            std::string yt_url = "https://youtu.be/"+yt_id;
             execl(
                 "/usr/bin/mpv",     // Путь к mpv
                 "mpv",              // Название файла
@@ -116,20 +185,62 @@ namespace components {
         }
     }
 
-    void MainWindow::onVideoBind(const Glib::RefPtr<Gtk::ListItem>& list_item)
+    void MainWindow::searchSidebarRegularMode()
     {
-        auto pos = list_item->get_position();
-        if (pos == GTK_INVALID_LIST_POSITION) return;
-        auto item = m_video_storage->get_item(pos);
+        // Получить иконку поиска и создать надпись "Поиск"
+        auto box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
+        box->set_valign(Gtk::Align::CENTER);
+
+        auto icon = Gio::Icon::create("find");
+        auto img_icon = Gtk::make_managed<Gtk::Image>(icon);
+        auto label = Gtk::make_managed<Gtk::Label>("Поиск видео");
+
+        box->append(*img_icon);
+        box->append(*label);
+
+        m_search_body.set_start_child(*box);
+    }
+
+    void MainWindow::searchSidebarVideoDetailsMode(
+            Glib::ustring title,
+            Glib::ustring channel_title,
+            Glib::ustring description,
+            std::string published_at,
+            std::string yt_id)
+    {
+        // Главный объект
+        auto layout = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
+        // Прокручиваемое окно
+        auto scroller = Gtk::make_managed<Gtk::ScrolledWindow>();
+        // Область деталей
+        auto box_details = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
+        // Область деталей (текст)
+        auto box_textdetails = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
+        // Область кнопок
+        auto box_buttons = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL);
         
-        auto box_main = dynamic_cast<Gtk::Box*>(list_item->get_child());
-        if (!box_main) return;
+        auto thumbnail = Gtk::make_managed<Gtk::Picture>();
+        auto lbl_title = Gtk::make_managed<Gtk::Label>();
+        auto lbl_channel_title = Gtk::make_managed<Gtk::Label>(channel_title);
+        auto lbl_description = Gtk::make_managed<Gtk::Label>(description);
+        auto lbl_published_at = Gtk::make_managed<Gtk::Label>(published_at);
 
-        auto thumbnail = dynamic_cast<Gtk::Picture*>(box_main->get_first_child());
-        if (!thumbnail) return;
+        // Установка названия видео (выделение полужирным)
+        lbl_title->set_markup("<b>"+title+"</b>");
 
-        // Загрузка изображения превью видео с диска
-        std::string thumbnail_path = "thumbnails/default/" + item->m_yt_id + ".jpg";
+        // Добавление кнопки "Воспроизвести"
+        auto btn_play = Gtk::make_managed<Gtk::Button>();
+        btn_play->set_child(*(core::getButtonContents("Воспроизвести", "player_play")));
+        btn_play->set_hexpand();
+        btn_play->signal_clicked().connect(sigc::bind(
+            sigc::mem_fun(*this, &MainWindow::playSingleVideo),
+            yt_id
+        ));
+        box_buttons->append(*btn_play);
+
+        // Скачивание большого превью
+        std::string thumbnail_path = "thumbnails/large/" + yt_id + ".jpg";
+        std::cout << thumbnail_path << std::endl;
         Glib::RefPtr<Gdk::Pixbuf> thumbnail_pixbuf;
         try {
             thumbnail_pixbuf = Gdk::Pixbuf::create_from_file(thumbnail_path);
@@ -137,7 +248,7 @@ namespace components {
             switch (e.code()) {
                 case Glib::FileError::Code::NO_SUCH_ENTITY:
                     // Превью на диске не найдено. Скачиваем...
-                    ytapi::downloadMediumThumnail(item->m_yt_id, thumbnail_path);
+                    ytapi::downloadLargeThumnail(yt_id, thumbnail_path);
                     // ...и присваиваем
                     thumbnail_pixbuf = Gdk::Pixbuf::create_from_file(thumbnail_path);
                     break;
@@ -149,44 +260,28 @@ namespace components {
         }
         auto thumbnail_texture = Gdk::Texture::create_for_pixbuf(thumbnail_pixbuf);
         thumbnail->set_paintable(thumbnail_texture);
-        thumbnail->set_can_shrink(false);
         thumbnail->set_content_fit(Gtk::ContentFit::COVER);
+        thumbnail->set_hexpand();
+        thumbnail->set_size_request(-1, 360);
 
-        auto lbl_title = dynamic_cast<Gtk::Label*>(thumbnail->get_next_sibling());
-        if (!lbl_title) return;
-
-        lbl_title->set_text(item->m_title);
-    }
+        lbl_description->set_halign(Gtk::Align::START);
+        lbl_description->set_selectable();
+        lbl_description->set_wrap();
 
-    // DO NOT USE!!
-    void MainWindow::onVideoSelected(unsigned int position)
-    {
-        std::cout << position;
-        auto item = m_video_storage->get_item(position);
-        if (!item) return;
+        box_textdetails->append(*lbl_title);
+        box_textdetails->append(*lbl_channel_title);
+        box_textdetails->append(*lbl_description);
+        box_textdetails->append(*lbl_published_at);
+        box_textdetails->set_margin(8);
 
-        std::string command = "mpv https://youtu.be/"+item->m_yt_id;
+        box_details->append(*thumbnail);
+        box_details->append(*box_textdetails);
+        box_details->set_vexpand();
+        scroller->set_child(*box_details);
 
-        std::cout << command;
-        system(command.c_str());
-    }
-
-    Gtk::Box* MainWindow::getButtonContents(Glib::ustring text, std::string icon_name)
-    {
-        // Создание иконки и текста
-        auto icon = Gio::Icon::create(icon_name);
-        auto img_icon = Gtk::make_managed<Gtk::Image>(icon);
-        auto lbl_main = Gtk::make_managed<Gtk::Label>(text);
-        lbl_main->set_hexpand(false);
-
-        // Добавление в контейнер
-        auto box_main = Gtk::make_managed<Gtk::Box>(
-            Gtk::Orientation::HORIZONTAL,
-            5
-        );
-        box_main->append(*img_icon);
-        box_main->append(*lbl_main);
+        layout->append(*scroller);
+        layout->append(*box_buttons);
 
-        return box_main;
+        m_search_body.set_start_child(*layout);
     }
 }

+ 50 - 39
src/YTMPV/MainWindow.hpp

@@ -1,63 +1,74 @@
 #pragma once
-#include <iostream>
+#include "VideoModel.hpp"
 #include <gtkmm/window.h>
-#include <gtkmm/button.h>
-#include <gtkmm/picture.h>
+#include <gtkmm/applicationwindow.h>
 #include <gtkmm/box.h>
-#include <gtkmm/label.h>
+#include <gtkmm/stack.h>
+#include <gtkmm/stackswitcher.h>
 #include <gtkmm/entry.h>
-#include <gtkmm/singleselection.h>
-#include <gtkmm/listview.h>
-#include <gtkmm/signallistitemfactory.h>
+#include <gtkmm/button.h>
 #include <gtkmm/scrolledwindow.h>
-
-#include <glibmm/ustring.h>
-#include <glibmm/fileutils.h>
-
-#include <gdkmm/pixbuf.h>
-#include <gdkmm/texture.h>
-
-#include <giomm/icon.h>
+#include <gtkmm/listview.h>
+#include <gtkmm/singleselection.h>
 #include <giomm/liststore.h>
-
-#include "VideoModel.hpp"
+#include <gtkmm/listitem.h>
+#include <gtkmm/paned.h>
 
 namespace components {
+
     // Главное окно приложения
-    class MainWindow : public Gtk::Window {
+    class MainWindow : public Gtk::ApplicationWindow
+    {
     public:
         MainWindow();
-        ~MainWindow() override;
 
     protected:
-        // --Обработка событий--
-        // Клик кнопки
+        Gtk::Box m_layout;
+        Gtk::Stack m_stack;
+        Gtk::StackSwitcher m_stackswitcher;
+
+        /// ПОИСК ///
+        // --Виджеты--
+        Gtk::Box m_search_layout;
+        // Панель поиска
+        Gtk::Box m_search_head;
+        // Тело
+        Gtk::Paned m_search_body;
+        // Поле ввода запроса
+        Gtk::Entry m_search_entry;
+        // Кнопка поиска
+        Gtk::Button m_search_button;
+        // Окно прокрутки для видео     
+        Gtk::ScrolledWindow m_search_scroller;
+        // Список видео
+        Gtk::ListView m_search_video_list;
+        // Список моделей видео
+        Glib::RefPtr<Gio::ListStore<components::VideoModel>> m_video_storage;
+        // Модель выбора
+        Glib::RefPtr<Gtk::SingleSelection> selection_model;
+
+        // --События--
+        // Клик кнопки поиска
         void onSearchButtonClicked();
         // При создании элемента в m_video_list
         void onVideoSetup(const Glib::RefPtr<Gtk::ListItem>& list_item);
         // При записи данных в m_video_list
         void onVideoBind(const Glib::RefPtr<Gtk::ListItem>& list_item);
         // При выборе видео из списка
-        void onVideoSelected(unsigned int position);
-
         void onVideoChanged();
 
-        // --Виджеты--
-        Gtk::Box                m_layout;       // Главный контейнер
-        // Поиск
-        Gtk::Box                m_search_box;   // Панель поиска
-        Gtk::Entry              m_search_field; // Поле ввода запроса
-        Gtk::Button             m_search_btn;   // Кнопка поиска
-        // Основное
-        Gtk::Box                m_body;         // Главное
-        Gtk::ScrolledWindow     m_video_scroll; // Окно прокрутки для видео
-        Gtk::ListView           m_video_list;   // Список видео
-
         // --Общее--
-        // Модель отображения видео
-        Glib::RefPtr<Gio::ListStore<VideoModel>> m_video_storage;
-        Glib::RefPtr<Gtk::SingleSelection> selection_model;
-        // Возвращает дочерний виджет для кнопок, которым нужны иконка с текстом
-        Gtk::Box* getButtonContents(Glib::ustring text, std::string icon_name);
+        // Устанавливает боковую панель просмотра видео в обычный режим
+        void searchSidebarRegularMode();
+        // Устанавливает боковую панель просмотра видео в режим просмотра
+        // информации о видео
+        void searchSidebarVideoDetailsMode(
+            Glib::ustring title,
+            Glib::ustring channel_title,
+            Glib::ustring description,
+            std::string published_at,
+            std::string yt_id);
+        // Проигрывает конкретное видео
+        void playSingleVideo(std::string yt_id);
     };
 }

+ 4 - 10
src/YTMPV/VideoModel.cpp

@@ -1,20 +1,14 @@
 #include "VideoModel.hpp"
 
 namespace components {
-    Glib::RefPtr<VideoModel> VideoModel::create(int id, std::string yt_id, const Glib::ustring& title)
+    Glib::RefPtr<VideoModel> VideoModel::create(db::video obj)
     {
         return Glib::make_refptr_for_instance<VideoModel>(
-            new VideoModel(
-                id,
-                yt_id,
-                title
-            )
+            new VideoModel(obj)
         );
     }
 
-    VideoModel::VideoModel(int id, std::string yt_id, const Glib::ustring& title)
-        : m_id(id)
-        , m_yt_id(yt_id)
-        , m_title(title)
+    VideoModel::VideoModel(db::video obj)
+        : m_obj {obj}
         {}
 }

+ 4 - 8
src/YTMPV/VideoModel.hpp

@@ -2,21 +2,17 @@
 #include <glibmm/ustring.h>
 #include <giomm/liststore.h>
 #include <string>
+#include <Database/entities.hpp>
 
 namespace components {
     class VideoModel : public Glib::Object
     {
     public:
-        // ID в БД
-        int m_id;
-        // ID на YouTube
-        std::string m_yt_id;
-        // Название видео
-        Glib::ustring m_title;
+        db::video m_obj;
         // Метод создания
-        static Glib::RefPtr<VideoModel> create(int id, std::string yt_id, const Glib::ustring& title);
+        static Glib::RefPtr<VideoModel> create(db::video obj);
 
     protected:
-        VideoModel(int id, std::string yt_id, const Glib::ustring& title);
+        VideoModel(db::video obj);
     };
 }

+ 28 - 0
src/YTMPV/app.cpp

@@ -0,0 +1,28 @@
+#include "app.hpp"
+
+namespace components {
+    App::App()
+        : Gtk::Application("com.github.aquadim.YTMPV")
+    {
+    }
+
+    Glib::RefPtr<App> App::create()
+    {
+        return Glib::make_refptr_for_instance<App>(new App());
+    }
+
+    void App::on_activate()
+    {
+        auto appwindow = create_appwindow();
+        appwindow->present();
+    }
+
+    MainWindow* App::create_appwindow()
+    {
+        // Создание окна и привязка обработчика к его сигналу скрытия
+        auto appwindow = new MainWindow();
+        add_window(*appwindow);
+        appwindow->signal_hide().connect([appwindow](){ delete appwindow; });
+        return appwindow;
+    }
+}

+ 21 - 0
src/YTMPV/app.hpp

@@ -0,0 +1,21 @@
+#pragma once
+#include <gtkmm/application.h>
+#include <glibmm/ustring.h>
+#include "MainWindow.hpp"
+
+namespace components {
+
+    // Класс приложения
+    class App: public Gtk::Application
+    {
+    public:
+        static Glib::RefPtr<App> create();
+
+    protected:
+        App();
+        void on_activate() override;
+
+    private:
+        MainWindow* create_appwindow();
+    };
+}

+ 23 - 1
src/YTMPV/core.cpp

@@ -1,8 +1,12 @@
 #include "core.hpp"
+#include <giomm/icon.h>
+#include <gtkmm/image.h>
+#include <gtkmm/label.h>
 
 namespace core {
     
-    db::video getVideoByYTID(std::string yt_id) {
+    db::video getVideoByYTID(std::string yt_id)
+    {
         db::video output;
 
         // 1. Проверить есть ли видео в базе данных
@@ -34,4 +38,22 @@ namespace core {
 
         return output;
     }
+
+    Gtk::Box* getButtonContents(Glib::ustring text, std::string icon_name)
+    {
+        // Создание иконки и текста
+        auto icon = Gio::Icon::create(icon_name);
+        auto img_icon = Gtk::make_managed<Gtk::Image>(icon);
+        auto lbl_main = Gtk::make_managed<Gtk::Label>(text);
+        lbl_main->set_hexpand(false);
+
+        // Добавление в контейнер
+        auto box_main = Gtk::make_managed<Gtk::Box>(
+            Gtk::Orientation::HORIZONTAL,
+            5);
+        box_main->append(*img_icon);
+        box_main->append(*lbl_main);
+
+        return box_main;
+    }
 }

+ 5 - 0
src/YTMPV/core.hpp

@@ -1,6 +1,8 @@
 #pragma once
 #include <YoutubeApi/youtubeapi.hpp>
 #include <Database/database.hpp>
+#include <gtkmm/box.h>
+#include <glibmm/ustring.h>
 #include <fstream>
 #include <iostream>
 #include <string>
@@ -8,4 +10,7 @@
 namespace core {
     // Возвращает объект видео по его Youtube id
     db::video getVideoByYTID(std::string yt_id);
+
+    // Возвращает дочерний виджет для кнопок, которым нужны иконка с текстом
+    Gtk::Box* getButtonContents(Glib::ustring text, std::string icon_name);
 }

+ 4 - 1
src/YTMPV/meson.build

@@ -1,6 +1,9 @@
 ytmpv = executable(
   'ytmpv',
-  ['ytmpv.cpp', 'core.cpp', 'MainWindow.cpp', 'VideoModel.cpp'],
+  [
+    'ytmpv.cpp', 'core.cpp', 'MainWindow.cpp', 'VideoModel.cpp',
+    'app.cpp'
+  ],
   link_with: [ytapi_lib, database_lib],
   include_directories: [dir_includes],
   dependencies: [glibmm_dep, curlpp_dep, json_dep, gtkmm_dep]

+ 0 - 0
src/YTMPV/views/BrowseVideosView.cpp


+ 0 - 0
src/YTMPV/views/BrowseVideosView.hpp


+ 0 - 0
src/YTMPV/views/View.cpp


+ 0 - 0
src/YTMPV/views/View.hpp


+ 3 - 4
src/YTMPV/ytmpv.cpp

@@ -1,5 +1,4 @@
-#include "MainWindow.hpp"
-#include <gtkmm/application.h>
+#include "app.hpp"
 #include <glibmm/optioncontext.h>
 #include <glibmm/optiongroup.h>
 #include <glibmm/optionentry.h>
@@ -51,8 +50,8 @@ int main(int argc, char** argv) {
     ytapi::youtubeInit(api_key);
 
     // ==Запуск приложения==
-    auto app = Gtk::Application::create("com.github.aquadim.YTMPV");
-    return app->make_window_and_run<components::MainWindow>(argc, argv);
+    auto app = components::App::create();
+    return app->run(argc, argv);
 
     //~ db::video found;
     //~ std::vector<std::string> video_ids = ytapi::getVideoIDsByQuery(argv[3]);

+ 2 - 0
thumbnails/large/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore