New controls (#106)
* make theme delete function general and clean it up * add steam big picture-like controls * aesthetic changes
This commit is contained in:
@@ -63,7 +63,7 @@ enum TextureID {
|
||||
TEXTURE_BATTERY_CHARGE,
|
||||
TEXTURE_QR,
|
||||
TEXTURE_PREVIEW,
|
||||
TEXTURE_SELECT_BUTTON, //Add the new select texture
|
||||
TEXTURE_SELECT_BUTTON,
|
||||
|
||||
TEXTURE_ICON, // always the last
|
||||
};
|
||||
|
||||
@@ -37,8 +37,10 @@ typedef enum {
|
||||
INSTALL_SINGLE,
|
||||
INSTALL_SHUFFLE,
|
||||
INSTALL_BGM,
|
||||
INSTALL_NO_BGM,
|
||||
|
||||
INSTALL_DOWNLOAD,
|
||||
INSTALL_ENTRY_DELETE,
|
||||
} InstallType;
|
||||
|
||||
typedef enum {
|
||||
@@ -46,15 +48,17 @@ typedef enum {
|
||||
ERROR_LEVEL_WARNING,
|
||||
} ErrorLevel;
|
||||
|
||||
#define BUTTONS_START_Y 140
|
||||
#define BUTTONS_STEP 25
|
||||
#define BUTTONS_START_Y 130
|
||||
#define BUTTONS_STEP 22
|
||||
|
||||
enum {
|
||||
BUTTONS_Y_PREVIEW = BUTTONS_START_Y+5,
|
||||
|
||||
BUTTONS_Y_LINE_1 = BUTTONS_START_Y + BUTTONS_STEP*1,
|
||||
|
||||
BUTTONS_Y_INFO = BUTTONS_Y_LINE_1+5,
|
||||
|
||||
BUTTONS_Y_LINE_2 = BUTTONS_START_Y + BUTTONS_STEP*2,
|
||||
BUTTONS_Y_LINE_3 = BUTTONS_START_Y + BUTTONS_STEP*3,
|
||||
BUTTONS_Y_LINE_4 = BUTTONS_START_Y + BUTTONS_STEP*4,
|
||||
|
||||
BUTTONS_X_LEFT = 20,
|
||||
BUTTONS_X_RIGHT = 200,
|
||||
@@ -70,6 +74,6 @@ void draw_preview(int preview_offset);
|
||||
|
||||
void draw_install(InstallType type);
|
||||
|
||||
void draw_interface(Entry_List_s* list, EntryMode current_mode);
|
||||
void draw_interface(Entry_List_s* list, EntryMode current_mode, bool install_mode);
|
||||
|
||||
#endif
|
||||
@@ -68,6 +68,7 @@ typedef struct {
|
||||
int shuffle_count;
|
||||
} Entry_List_s;
|
||||
|
||||
void delete_entry(Entry_s entry);
|
||||
Result load_entries(const char * loading_path, Entry_List_s * list);
|
||||
bool load_preview(Entry_List_s list, int * preview_offset);
|
||||
u32 load_data(char * filename, Entry_s entry, char ** buf);
|
||||
|
||||
@@ -69,8 +69,6 @@ typedef struct {
|
||||
u32 shuffle_music_sizes[MAX_SHUFFLE_THEMES];
|
||||
} ThemeManage_bin_s;
|
||||
|
||||
void delete_theme(Entry_s theme);
|
||||
|
||||
Result theme_install(Entry_s theme);
|
||||
Result no_bgm_install(Entry_s theme);
|
||||
Result bgm_install(Entry_s theme);
|
||||
|
||||
@@ -56,7 +56,7 @@ void init_screens(void)
|
||||
pp2d_load_texture_png(TEXTURE_BATTERY_4, "romfs:/battery4.png");
|
||||
pp2d_load_texture_png(TEXTURE_BATTERY_5, "romfs:/battery5.png");
|
||||
pp2d_load_texture_png(TEXTURE_BATTERY_CHARGE, "romfs:/charging.png");
|
||||
pp2d_load_texture_png(TEXTURE_SELECT_BUTTON, "romfs:/select.png"); //Load new select PNG
|
||||
pp2d_load_texture_png(TEXTURE_SELECT_BUTTON, "romfs:/select.png");
|
||||
}
|
||||
|
||||
void exit_screens(void)
|
||||
@@ -144,7 +144,7 @@ void draw_install(InstallType type)
|
||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing shuffle themes...");
|
||||
break;
|
||||
case INSTALL_BGM:
|
||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing BGM...");
|
||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing BGM-only theme...");
|
||||
break;
|
||||
case INSTALL_DOWNLOAD:
|
||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Downloading...");
|
||||
@@ -155,32 +155,38 @@ void draw_install(InstallType type)
|
||||
case INSTALL_SPLASH_DELETE:
|
||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Deleting installed splash...");
|
||||
break;
|
||||
case INSTALL_ENTRY_DELETE:
|
||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Deleting from SD...");
|
||||
break;
|
||||
case INSTALL_NO_BGM:
|
||||
pp2d_draw_text_center(GFX_TOP, 120, 0.8, 0.8, COLOR_WHITE, "Installing theme without BGM...");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pp2d_end_draw();
|
||||
}
|
||||
|
||||
void draw_interface(Entry_List_s* list, EntryMode current_mode)
|
||||
void draw_interface(Entry_List_s* list, EntryMode current_mode, bool install_mode)
|
||||
{
|
||||
draw_base_interface();
|
||||
|
||||
const char* mode_string[] = {
|
||||
const char* mode_string[MODE_AMOUNT] = {
|
||||
"Theme mode",
|
||||
"Splashes mode",
|
||||
"Splash mode",
|
||||
};
|
||||
|
||||
pp2d_draw_text_center(GFX_TOP, 4, 0.5, 0.5, COLOR_WHITE, mode_string[current_mode]);
|
||||
|
||||
if(list->entries == NULL)
|
||||
{
|
||||
const char* mode_found_string[] = {
|
||||
const char* mode_found_string[MODE_AMOUNT] = {
|
||||
"No themes found",
|
||||
"No splashes found",
|
||||
};
|
||||
pp2d_draw_text_center(GFX_TOP, 80, 0.7, 0.7, COLOR_YELLOW, mode_found_string[current_mode]);
|
||||
pp2d_draw_text_center(GFX_TOP, 110, 0.7, 0.7, COLOR_YELLOW, "Press \uE005 to download from QR");
|
||||
const char* mode_switch_string[] = {
|
||||
const char* mode_switch_string[MODE_AMOUNT] = {
|
||||
"Or \uE004 to switch to splashes",
|
||||
"Or \uE004 to switch to themes",
|
||||
};
|
||||
@@ -205,33 +211,46 @@ void draw_interface(Entry_List_s* list, EntryMode current_mode)
|
||||
utf16_to_utf32((u32*)description, current_entry.desc, 0x80);
|
||||
pp2d_draw_wtext_wrap(20, 65, 0.5, 0.5, COLOR_WHITE, 363, description);
|
||||
|
||||
|
||||
switch(current_mode)
|
||||
if(install_mode)
|
||||
{
|
||||
case MODE_THEMES:
|
||||
pp2d_draw_text_center(GFX_TOP, BUTTONS_Y_PREVIEW, 0.6, 0.6, COLOR_WHITE, "\uE003 Preview Theme");
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to Splashes");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QRCode");
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE079 Normal install");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE07A Shuffle install");
|
||||
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install Theme");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE001 Queue Shuffle");
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE07B BGM-only install");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE07C No-BGM install");
|
||||
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE002 Install BGM");
|
||||
pp2d_draw_texture(TEXTURE_SELECT_BUTTON, BUTTONS_X_RIGHT -38, BUTTONS_Y_LINE_3 + 3); //Draw select in place of old minus
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"Install Shuffle Themes");
|
||||
break;
|
||||
case MODE_SPLASHES:
|
||||
pp2d_draw_text_center(GFX_TOP, BUTTONS_Y_PREVIEW, 0.6, 0.6, COLOR_WHITE, "\uE003 Preview Splash");
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to Themes");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QRCode");
|
||||
pp2d_draw_text_center(GFX_TOP, BUTTONS_Y_LINE_1, 0.55, 0.55, COLOR_WHITE, "Release \uE000 to cancel or hold \uE006 and release \uE000 to install");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(current_mode)
|
||||
{
|
||||
case MODE_THEMES:
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE000 Hold to install");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE001 Queue shuffle theme");
|
||||
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install Splash");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE001 Delete installed Splash");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE003 Preview theme");
|
||||
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to splashes");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QR code");
|
||||
break;
|
||||
case MODE_SPLASHES:
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE000 Install splash");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_1, 0.6, 0.6, COLOR_WHITE, L"\uE001 Delete installed splash");
|
||||
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_2, 0.6, 0.6, COLOR_WHITE, L"\uE003 Preview splash");
|
||||
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE004 Switch to themes");
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT, BUTTONS_Y_LINE_3, 0.6, 0.6, COLOR_WHITE, L"\uE005 Scan QR code");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pp2d_draw_texture(TEXTURE_SELECT_BUTTON, BUTTONS_X_RIGHT-10, BUTTONS_Y_LINE_4 + 3);
|
||||
pp2d_draw_wtext(BUTTONS_X_RIGHT+26, BUTTONS_Y_LINE_4, 0.6, 0.6, COLOR_WHITE, L"Delete from SD");
|
||||
}
|
||||
|
||||
pp2d_draw_wtext(BUTTONS_X_LEFT, BUTTONS_Y_LINE_4, 0.6, 0.6, COLOR_WHITE, L"\uE045 Exit");
|
||||
|
||||
pp2d_draw_on(GFX_BOTTOM, GFX_LEFT);
|
||||
|
||||
|
||||
@@ -30,6 +30,14 @@
|
||||
#include "unicode.h"
|
||||
#include "draw.h"
|
||||
|
||||
void delete_entry(Entry_s entry)
|
||||
{
|
||||
if(entry.is_zip)
|
||||
FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_UTF16, entry.path));
|
||||
else
|
||||
FSUSER_DeleteDirectoryRecursively(ArchiveSD, fsMakePath(PATH_UTF16, entry.path));
|
||||
}
|
||||
|
||||
u32 load_data(char * filename, Entry_s entry, char ** buf)
|
||||
{
|
||||
if(entry.is_zip)
|
||||
|
||||
160
source/main.c
160
source/main.c
@@ -136,18 +136,20 @@ int main(void)
|
||||
int preview_offset = 0;
|
||||
|
||||
bool qr_mode = false;
|
||||
bool install_mode = false;
|
||||
|
||||
while(aptMainLoop())
|
||||
{
|
||||
hidScanInput();
|
||||
u32 kDown = hidKeysDown();
|
||||
u32 kHeld = hidKeysHeld();
|
||||
u32 kUp = hidKeysUp();
|
||||
|
||||
Entry_List_s * current_list = &lists[current_mode];
|
||||
|
||||
if(qr_mode) take_picture();
|
||||
else if(preview_mode) draw_preview(preview_offset);
|
||||
else draw_interface(current_list, current_mode);
|
||||
else draw_interface(current_list, current_mode, install_mode);
|
||||
pp2d_end_draw();
|
||||
|
||||
if(kDown & KEY_START) break;
|
||||
@@ -158,53 +160,52 @@ int main(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!preview_mode && !qr_mode && kDown & KEY_L) //toggle between splashes and themes
|
||||
if(!install_mode)
|
||||
{
|
||||
current_mode++;
|
||||
current_mode %= MODE_AMOUNT;
|
||||
continue;
|
||||
}
|
||||
else if(!preview_mode && kDown & KEY_R) //toggle QR mode
|
||||
{
|
||||
u32 out;
|
||||
ACU_GetWifiStatus(&out);
|
||||
if(out)
|
||||
if(!preview_mode && !qr_mode && kDown & KEY_L) //toggle between splashes and themes
|
||||
{
|
||||
qr_mode = !qr_mode;
|
||||
if(qr_mode)
|
||||
init_qr();
|
||||
current_mode++;
|
||||
current_mode %= MODE_AMOUNT;
|
||||
continue;
|
||||
}
|
||||
else if(!preview_mode && kDown & KEY_R) //toggle QR mode
|
||||
{
|
||||
u32 out;
|
||||
ACU_GetWifiStatus(&out);
|
||||
if(out)
|
||||
{
|
||||
qr_mode = !qr_mode;
|
||||
if(qr_mode)
|
||||
init_qr();
|
||||
else
|
||||
exit_qr();
|
||||
}
|
||||
else
|
||||
exit_qr();
|
||||
{
|
||||
throw_error("Please connect to Wi-Fi before scanning QR", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
else if(!qr_mode && kDown & KEY_Y) //toggle preview mode
|
||||
{
|
||||
throw_error("Please connect to Wi-Fi before scanning QR", ERROR_LEVEL_WARNING);
|
||||
if(!preview_mode)
|
||||
preview_mode = load_preview(*current_list, &preview_offset);
|
||||
else
|
||||
preview_mode = false;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if(!qr_mode && kDown & KEY_Y) //toggle preview mode
|
||||
{
|
||||
if(!preview_mode)
|
||||
else if(qr_mode && kDown & KEY_L) //scan a QR code while in QR mode
|
||||
{
|
||||
preview_mode = load_preview(*current_list, &preview_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
preview_mode = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if(qr_mode && kDown & KEY_L) //scan a QR code while in QR mode
|
||||
{
|
||||
CAMU_StopCapture(PORT_BOTH);
|
||||
CAMU_Activate(SELECT_NONE);
|
||||
qr_mode = !scan_qr(current_mode);
|
||||
CAMU_Activate(SELECT_OUT1_OUT2);
|
||||
CAMU_StartCapture(PORT_BOTH);
|
||||
CAMU_StopCapture(PORT_BOTH);
|
||||
CAMU_Activate(SELECT_NONE);
|
||||
qr_mode = !scan_qr(current_mode);
|
||||
CAMU_Activate(SELECT_OUT1_OUT2);
|
||||
CAMU_StartCapture(PORT_BOTH);
|
||||
|
||||
if(!qr_mode)
|
||||
load_lists(lists);
|
||||
continue;
|
||||
if(!qr_mode)
|
||||
load_lists(lists);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(qr_mode || preview_mode || current_list->entries == NULL)
|
||||
@@ -213,28 +214,57 @@ int main(void)
|
||||
int selected_entry = current_list->selected_entry;
|
||||
Entry_s * current_entry = ¤t_list->entries[selected_entry];
|
||||
|
||||
// Actions
|
||||
if(kDown & KEY_X)
|
||||
if(install_mode)
|
||||
{
|
||||
switch(current_mode)
|
||||
if(kUp & KEY_A)
|
||||
install_mode = false;
|
||||
if(!install_mode)
|
||||
{
|
||||
case MODE_THEMES:
|
||||
if((kDown | kHeld) & KEY_DLEFT)
|
||||
{
|
||||
draw_install(INSTALL_BGM);
|
||||
bgm_install(*current_entry);
|
||||
break;
|
||||
case MODE_SPLASHES:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else if((kDown | kHeld) & KEY_DUP)
|
||||
{
|
||||
draw_install(INSTALL_SINGLE);
|
||||
theme_install(*current_entry);
|
||||
}
|
||||
else if((kDown | kHeld) & KEY_DRIGHT)
|
||||
{
|
||||
draw_install(INSTALL_NO_BGM);
|
||||
no_bgm_install(*current_entry);
|
||||
}
|
||||
else if((kDown | kHeld) & KEY_DDOWN)
|
||||
{
|
||||
if(current_list->shuffle_count > MAX_SHUFFLE_THEMES)
|
||||
{
|
||||
throw_error("You have too many themes selected.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
else if(current_list->shuffle_count == 0)
|
||||
{
|
||||
throw_error("You dont have any themes selected.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
else
|
||||
{
|
||||
draw_install(INSTALL_SHUFFLE);
|
||||
Result res = shuffle_install(*current_list);
|
||||
if(R_FAILED(res)) DEBUG("shuffle install result: %lx\n", res);
|
||||
else current_list->shuffle_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if(kDown & KEY_A)
|
||||
|
||||
// Actions
|
||||
|
||||
if(kDown & KEY_A)
|
||||
{
|
||||
switch(current_mode)
|
||||
{
|
||||
case MODE_THEMES:
|
||||
draw_install(INSTALL_SINGLE);
|
||||
theme_install(*current_entry);
|
||||
install_mode = true;
|
||||
break;
|
||||
case MODE_SPLASHES:
|
||||
draw_install(INSTALL_SPLASH);
|
||||
@@ -261,32 +291,24 @@ int main(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if(kDown & KEY_SELECT)
|
||||
else if(kDown & KEY_X)
|
||||
{
|
||||
switch(current_mode)
|
||||
{
|
||||
case MODE_THEMES:
|
||||
if(current_list->shuffle_count > MAX_SHUFFLE_THEMES)
|
||||
{
|
||||
throw_error("You have too many Shuffle selected.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
else if(current_list->shuffle_count == 0)
|
||||
{
|
||||
throw_error("You dont have any Shuffle selected.", ERROR_LEVEL_WARNING);
|
||||
}
|
||||
else
|
||||
{
|
||||
draw_install(INSTALL_SHUFFLE);
|
||||
Result res = shuffle_install(*current_list);
|
||||
if(R_FAILED(res)) DEBUG("shuffle install result: %lx\n", res);
|
||||
else current_list->shuffle_count = 0;
|
||||
}
|
||||
break;
|
||||
case MODE_SPLASHES:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(kDown & KEY_SELECT)
|
||||
{
|
||||
draw_install(INSTALL_ENTRY_DELETE);
|
||||
delete_entry(*current_entry);
|
||||
load_lists(lists);
|
||||
}
|
||||
|
||||
// Movement in the UI
|
||||
else if(kDown & KEY_UP)
|
||||
|
||||
@@ -32,20 +32,6 @@
|
||||
#define BODY_CACHE_SIZE 0x150000
|
||||
#define BGM_MAX_SIZE 0x337000
|
||||
|
||||
void delete_theme(Entry_s theme)
|
||||
{
|
||||
Handle dir_handle;
|
||||
Result res = FSUSER_OpenDirectory(&dir_handle, ArchiveSD, fsMakePath(PATH_UTF16, theme.path));
|
||||
if(R_SUCCEEDED(res))
|
||||
{
|
||||
FSDIR_Close(dir_handle);
|
||||
FSUSER_DeleteDirectoryRecursively(ArchiveSD, fsMakePath(PATH_UTF16, theme.path));
|
||||
} else
|
||||
{
|
||||
FSUSER_DeleteFile(ArchiveSD, fsMakePath(PATH_UTF16, theme.path));
|
||||
}
|
||||
}
|
||||
|
||||
static Result install_theme_internal(Entry_List_s themes, int installmode)
|
||||
{
|
||||
Result res = 0;
|
||||
|
||||
Reference in New Issue
Block a user