mirror of
https://github.com/zebrajr/SamRewritten.git
synced 2025-12-06 00:19:47 +01:00
Did async download of images
This commit is contained in:
parent
8657d27949
commit
bc13750209
|
|
@ -28,14 +28,6 @@ m_builder(nullptr)
|
|||
|
||||
// See https://stackoverflow.com/questions/9192223/remove-gtk-container-children-repopulate-it-then-refresh
|
||||
void MainPickerWindow::reset_game_list() {
|
||||
/*GList *children, *iter;
|
||||
children = gtk_container_get_children(GTK_CONTAINER(m_game_list));
|
||||
|
||||
for(iter = children; iter != NULL; iter = g_list_next(iter))
|
||||
gtk_widget_destroy(GTK_WIDGET(iter->data));
|
||||
|
||||
g_list_free(children);*/
|
||||
|
||||
gtk_container_foreach(GTK_CONTAINER(m_game_list), (GtkCallback)gtk_widget_destroy, NULL);
|
||||
//TODO refresh the view but I dont know how to
|
||||
|
||||
|
|
@ -60,6 +52,7 @@ void MainPickerWindow::add_to_game_list(const Game_t& app) {
|
|||
#pragma GCC diagnostic pop
|
||||
|
||||
gtk_widget_set_size_request(wrapper, -1, 80);
|
||||
gtk_buildable_set_name(GTK_BUILDABLE(game_logo), std::to_string(app.app_id).c_str());
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(layout), GTK_WIDGET(game_logo), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(layout), GTK_WIDGET(label), TRUE, TRUE, 0);
|
||||
|
|
@ -74,4 +67,29 @@ void MainPickerWindow::add_to_game_list(const Game_t& app) {
|
|||
void MainPickerWindow::confirm_game_list() {
|
||||
gtk_widget_show_all(GTK_WIDGET(m_game_list));
|
||||
// Show all widgetss
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainPickerWindow::refresh_app_icon(const unsigned long app_id) {
|
||||
|
||||
std::cerr << "Gotta renew " << app_id << "'s icon" << std::endl;
|
||||
|
||||
GList *children, *iter;
|
||||
char id[256];
|
||||
char req_id[256];
|
||||
|
||||
children = gtk_container_get_children(GTK_CONTAINER(m_game_list));
|
||||
strncpy(req_id, std::to_string(app_id).c_str(), 256);
|
||||
|
||||
std::cerr << "length: " << g_list_length(children); //0 TO DEBUG
|
||||
|
||||
for(iter = children; iter != NULL; iter = g_list_next(iter)) {
|
||||
strncpy(id, gtk_buildable_get_name(GTK_BUILDABLE(iter->data)), 256);
|
||||
if(strcmp(id, req_id) == 0) {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free(children);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
class MainPickerWindow {
|
||||
public:
|
||||
//Todo: destructor
|
||||
//Todo: destructor and tidy
|
||||
MainPickerWindow();
|
||||
void reset_game_list();
|
||||
void add_to_game_list(const Game_t& app);
|
||||
void confirm_game_list();
|
||||
void refresh_app_icon(const unsigned long app_id);
|
||||
GtkWidget* get_main_window() { return m_main_window; };
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -82,9 +82,10 @@ void MySteam::refresh_owned_apps() {
|
|||
const std::string input_scheme_c(prefix + "%lu.bin");
|
||||
Game_t game;
|
||||
unsigned long app_id;
|
||||
SteamAppDAO* appDAO = SteamAppDAO::get_instance();
|
||||
|
||||
// The whole update will really occur only once in a while, no worries
|
||||
SteamAppDAO::update_name_database();
|
||||
appDAO->update_name_database();
|
||||
m_all_subscribed_apps.clear();
|
||||
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
|
|
@ -92,8 +93,8 @@ void MySteam::refresh_owned_apps() {
|
|||
if(filename.rfind(prefix, 0) == 0) {
|
||||
if(sscanf(dp->d_name, input_scheme_c.c_str(), &app_id) == 1) {
|
||||
game.app_id = app_id;
|
||||
game.app_name = SteamAppDAO::get_app_name(app_id);
|
||||
SteamAppDAO::download_app_icon(app_id);
|
||||
game.app_name = appDAO->get_app_name(app_id);
|
||||
appDAO->download_app_icon(app_id);
|
||||
|
||||
m_all_subscribed_apps.push_back(game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ SteamAppDAO::update_name_database() {
|
|||
}
|
||||
|
||||
if(need_to_redownload) {
|
||||
SteamAppDAO::download_file("http://api.steampowered.com/ISteamApps/GetAppList/v0002/", local_file_name);
|
||||
Downloader::get_instance()->download_file("http://api.steampowered.com/ISteamApps/GetAppList/v0002/", local_file_name, 0);
|
||||
SteamAppDAO::parse_app_names();
|
||||
}
|
||||
}
|
||||
|
|
@ -72,43 +72,7 @@ SteamAppDAO::download_app_icon(const unsigned long& app_id) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(!file_exists(local_path)){
|
||||
SteamAppDAO::download_file(url, local_path);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SteamAppDAO::download_file(const std::string& file_url, const std::string& local_path) {
|
||||
std::cerr << "Downloading " << file_url << std::endl;
|
||||
|
||||
CURL *curl;
|
||||
FILE *fp;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (curl) {
|
||||
fp = fopen(local_path.c_str(),"wb");
|
||||
curl_easy_setopt(curl, CURLOPT_URL, file_url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||
res = curl_easy_perform(curl);
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
fclose(fp);
|
||||
}
|
||||
else {
|
||||
std::cerr << "An error occurred creating curl. Please report to the developers!" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(res != 0) {
|
||||
std::cerr << "Curl returned with status " << res << ", which is unexpected. Make sure you are connected to the internet, and you have access";
|
||||
std::cerr << " to Steam, and try again." << std::endl;
|
||||
std::cerr << "Unable to fetch file " << file_url << std::endl;
|
||||
//TODO make a gui for this
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
Downloader::get_instance()->download_file_async(url, local_path, app_id);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -162,4 +126,9 @@ SteamAppDAO::parse_app_names() {
|
|||
std::cerr << "Could not retrieve app names. Unable to open " << file_path << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SteamAppDAO::update(unsigned long i) {
|
||||
g_main_gui->refresh_app_icon(i);
|
||||
}
|
||||
|
|
@ -5,41 +5,53 @@
|
|||
#include <ctime>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <curl/curl.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "../common/c_processes.h"
|
||||
#include "../common/Downloader.h"
|
||||
#include "globals.h"
|
||||
|
||||
class SteamAppDAO {
|
||||
class SteamAppDAO : public Observer<unsigned long> {
|
||||
public:
|
||||
//TODO tidy
|
||||
static SteamAppDAO* get_instance() {
|
||||
static SteamAppDAO me;
|
||||
return &me;
|
||||
}
|
||||
/**
|
||||
* Redownloads http://api.steampowered.com/ISteamApps/GetAppList/v0002/
|
||||
* if necessary. Redownloads every few days.
|
||||
* TODO: Maybe pass a boolean too as argument for "Override redownload"
|
||||
*/
|
||||
static void update_name_database();
|
||||
void update_name_database();
|
||||
|
||||
/**
|
||||
* Feed it an appId, returns the app name.
|
||||
* Make sure to call update_name_database at least once
|
||||
* before using.
|
||||
*/
|
||||
static std::string get_app_name(const unsigned long& app_id);
|
||||
std::string get_app_name(const unsigned long& app_id);
|
||||
|
||||
/**
|
||||
* Download the app's banner ASYNCHRONOUSLY.
|
||||
* If it fails, nothing is written.
|
||||
*/
|
||||
static void download_app_icon(const unsigned long& app_id);
|
||||
void download_app_icon(const unsigned long& app_id);
|
||||
|
||||
/**
|
||||
* Path name to the root of the cache folder. By now it is
|
||||
* ~/.SamRewritten
|
||||
*/
|
||||
static const char *CACHE_FOLDER;
|
||||
static const char* CACHE_FOLDER;
|
||||
|
||||
//TODO tidy
|
||||
void update(unsigned long i);
|
||||
|
||||
SteamAppDAO(SteamAppDAO const&) = delete;
|
||||
void operator=(SteamAppDAO const&) = delete;
|
||||
private:
|
||||
static void download_file(const std::string& file_url, const std::string& local_path);
|
||||
SteamAppDAO() {Downloader::get_instance()->attach(this);};
|
||||
~SteamAppDAO() {};
|
||||
static void parse_app_names();
|
||||
|
||||
static std::map<unsigned long, std::string> m_app_names;
|
||||
|
|
|
|||
9
SAM.Picker/globals.h
Normal file
9
SAM.Picker/globals.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
class MySteam;
|
||||
#include "MainPickerWindow.h"
|
||||
//TODO tidy & comment
|
||||
//Globals
|
||||
//Reason for the globals is that it's easier to access them in GTK callbacks
|
||||
extern MySteam *g_steam; // The Model
|
||||
extern MainPickerWindow *g_main_gui; // The view
|
||||
|
|
@ -4,20 +4,17 @@
|
|||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gmodule.h>
|
||||
#include "MySteam.h"
|
||||
#include "MainPickerWindow.h"
|
||||
#include "SteamAppDAO.h"
|
||||
#include "globals.h"
|
||||
|
||||
int launcher_main();
|
||||
|
||||
//Globals
|
||||
//Reason for the globals is that it's easier to access them in GTK callbacks
|
||||
MySteam *g_steam = nullptr; // The Model
|
||||
MainPickerWindow *g_main_gui = nullptr; // The view
|
||||
MySteam* g_steam = nullptr;
|
||||
MainPickerWindow* g_main_gui = nullptr;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
|
|
|
|||
45
common/Downloader.cpp
Normal file
45
common/Downloader.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "Downloader.h"
|
||||
|
||||
void
|
||||
Downloader::download_file(const std::string& file_url, const std::string& local_path, const unsigned long& dl_id) {
|
||||
//If the file exists, there's no need to download it again.
|
||||
//We assume the banners don't change
|
||||
if(!file_exists(local_path)) {
|
||||
CURL *curl;
|
||||
FILE *fp;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (curl) {
|
||||
fp = fopen(local_path.c_str(),"wb");
|
||||
curl_easy_setopt(curl, CURLOPT_URL, file_url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||
res = curl_easy_perform(curl);
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
fclose(fp);
|
||||
}
|
||||
else {
|
||||
std::cerr << "An error occurred creating curl. Please report to the developers!" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(res != 0) {
|
||||
std::cerr << "Curl returned with status " << res << ", which is unexpected. Make sure you are connected to the internet, and you have access";
|
||||
std::cerr << " to Steam, and try again." << std::endl;
|
||||
std::cerr << "Unable to fetch file " << file_url << std::endl;
|
||||
//TODO make a gui for this
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
notify(dl_id);
|
||||
}
|
||||
|
||||
void
|
||||
Downloader::download_file_async(const std::string& file_url, const std::string& local_path, const unsigned long& dl_id) {
|
||||
//std::async(std::launch::async, &Downloader::download_file, this, file_url, local_path, dl_id);
|
||||
std::async([this, file_url, local_path, dl_id]{this->download_file(file_url, local_path, dl_id);});
|
||||
}
|
||||
29
common/Downloader.h
Normal file
29
common/Downloader.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef DOWNLOADER
|
||||
#define DOWNLOADER
|
||||
|
||||
#pragma once
|
||||
#include "ObserverClasses.h"
|
||||
#include "c_processes.h"
|
||||
#include <curl/curl.h>
|
||||
#include <string>
|
||||
#include <future>
|
||||
|
||||
//TODO comment & tidy
|
||||
|
||||
class Downloader : public Subject<unsigned long> {
|
||||
public:
|
||||
static Downloader* get_instance() {
|
||||
static Downloader me;
|
||||
return &me;
|
||||
};
|
||||
void download_file(const std::string& file_url, const std::string& local_path, const unsigned long& dl_id);
|
||||
void download_file_async(const std::string& file_url, const std::string& local_path, const unsigned long& dl_id);
|
||||
|
||||
Downloader(Downloader const&) = delete;
|
||||
void operator=(Downloader const&) = delete;
|
||||
private:
|
||||
Downloader() {};
|
||||
~Downloader() {};
|
||||
};
|
||||
|
||||
#endif
|
||||
32
common/ObserverClasses.h
Normal file
32
common/ObserverClasses.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* This is a really limited observer pattern.
|
||||
* It's not fully implemented on purpose. For now,
|
||||
* Ther's no need for more advanced functions.
|
||||
*/
|
||||
|
||||
template<typename T> class Observer;
|
||||
|
||||
template <typename T>
|
||||
class Subject {
|
||||
vector < class Observer<T> * > views;
|
||||
|
||||
public:
|
||||
void attach(Observer<T> *obs) {
|
||||
views.push_back(obs);
|
||||
};
|
||||
|
||||
void notify(T usr_data) {
|
||||
for(Observer<T>* obs : views)
|
||||
obs->update(usr_data);
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Observer {
|
||||
public:
|
||||
virtual void update(T) = 0;
|
||||
};
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.20.2 -->
|
||||
<!-- Generated with glade 3.20.3 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkListBoxRow" id="game_entry">
|
||||
|
|
@ -145,6 +145,18 @@
|
|||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkPopover" id="search_popover">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkSearchEntry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="primary_icon_name">edit-find-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkApplicationWindow" id="main_window">
|
||||
<property name="width_request">800</property>
|
||||
<property name="height_request">500</property>
|
||||
|
|
@ -233,6 +245,26 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="popover">search_popover</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-find-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
4
make.sh
4
make.sh
|
|
@ -5,8 +5,8 @@ SCRIPTPATH=`dirname $SCRIPT`
|
|||
|
||||
#export LD_LIBRARY_PATH=$SCRIPTPATH/bin
|
||||
|
||||
g++ -g `pkg-config --cflags gtk+-3.0` -rdynamic -export-dynamic -Wall SAM.Picker/*.cpp common/*.cpp -L$SCRIPTPATH/bin -o $SCRIPTPATH/bin/samrewritten `pkg-config --libs gtk+-3.0` -lgmodule-2.0 -lsteam_api -lcurl \
|
||||
g++ -g `pkg-config --cflags gtk+-3.0` -rdynamic -export-dynamic -pthread -Wall SAM.Picker/*.cpp common/*.cpp -L$SCRIPTPATH/bin -o $SCRIPTPATH/bin/samrewritten `pkg-config --libs gtk+-3.0` -lpthread -lgmodule-2.0 -lsteam_api -lcurl \
|
||||
&& \
|
||||
g++ -g SAM.Game/*.cpp common/*.cpp -lsteam_api -L$SCRIPTPATH/bin -o $SCRIPTPATH/bin/samgame \
|
||||
g++ -g SAM.Game/*.cpp common/c_processes.cpp common/lodepng.cpp -lsteam_api -L$SCRIPTPATH/bin -o $SCRIPTPATH/bin/samgame \
|
||||
&& \
|
||||
./bin/launch.sh
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user