Feature/bookmarks (#487)

* wip

* add symlink functions

* introduce symlink drawing

* remove warnings

* add symlink theme

* wip

* better magic number compare

* wip

* wip

* refactoring

* resolve links

* add theme

* nested dir symlink contxt

* nested symlinks with correct sel position

* remove todos

* wip non compiling

* archive mode

* resolve files

* add context menu

* resolve files correctly

* err code

* add shortcut for bookmarks

* recent files

* l/r switching

* wip

* menu changes

* bookmark dialog

* wip

* add sort mode

* recent files

* dont store parent dir in recent files

* clean up

* recent menu entry

* error msgs

* code style ptr

* arrow

* new menu entries

* remapping shortcuts

* introduce symlink ext

* fix symlink extension

* file extension behaviour for folders

* clean recent files

* typo

* change order of delete for recent folder

* use left arrow key for shortcut not L key

* skip symlink hierarchies when pressing O in bookmarks/ recent files

* hide new bookmark entry when bookmark folder selected
This commit is contained in:
Andrin Bertschi 2018-09-13 12:00:30 +02:00 committed by TheOfficialFloW
parent 4364101491
commit 8eff0e6bba
16 changed files with 796 additions and 137 deletions

190
file.c
View File

@ -25,26 +25,28 @@
#include "strnatcmp.h"
static char *devices[] = {
"gro0:",
"grw0:",
"imc0:",
"os0:",
"pd0:",
"sa0:",
"sd0:",
"tm0:",
"ud0:",
"uma0:",
"ur0:",
"ux0:",
"vd0:",
"vs0:",
"xmc0:",
"host0:",
"gro0:",
"grw0:",
"imc0:",
"os0:",
"pd0:",
"sa0:",
"sd0:",
"tm0:",
"ud0:",
"uma0:",
"ur0:",
"ux0:",
"vd0:",
"vs0:",
"xmc0:",
"host0:",
};
#define N_DEVICES (sizeof(devices) / sizeof(char **))
const char symlink_header_bytes[SYMLINK_HEADER_SIZE] = {0xF1, 0x1E, 0x00, 0x00};
int allocateReadFile(const char *file, void **buffer) {
SceUID fd = sceIoOpen(file, SCE_O_RDONLY, 0);
if (fd < 0)
@ -436,13 +438,13 @@ int copyPath(const char *src_path, const char *dst_path, FileProcessParam *param
sceIoGetstatByFd(dfd, &stat);
stat.st_mode |= SCE_S_IWUSR;
int ret = sceIoMkdir(dst_path, stat.st_mode & 0xFFF);
if (ret < 0 && ret != SCE_ERROR_ERRNO_EEXIST) {
sceIoDclose(dfd);
return ret;
}
if (ret == SCE_ERROR_ERRNO_EEXIST) {
sceIoChstat(dst_path, &stat, 0x3B);
}
@ -756,12 +758,12 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
char entry_name[MAX_NAME_LENGTH];
strcpy(entry_name, entry->name);
removeEndSlash(entry_name);
while (p) {
char p_name[MAX_NAME_LENGTH];
strcpy(p_name, p->name);
removeEndSlash(p_name);
// '..' is always at first
if (strcmp(entry_name, "..") == 0)
break;
@ -842,7 +844,7 @@ void fileListAddEntry(FileList *list, FileListEntry *entry, int sort) {
list->tail = entry;
} else { // Order: previous -> entry -> p
previous->next = entry;
entry->previous = previous;
entry->previous = previous;
entry->next = p;
p->previous = entry;
}
@ -965,6 +967,7 @@ int fileListGetDeviceEntries(FileList *list) {
strcpy(entry->name, devices[i]);
entry->is_folder = 1;
entry->type = FILE_TYPE_UNKNOWN;
entry->is_symlink = 0;
SceIoDevInfo info;
memset(&info, 0, sizeof(SceIoDevInfo));
@ -981,9 +984,9 @@ int fileListGetDeviceEntries(FileList *list) {
}
}
memcpy(&entry->ctime, (SceDateTime *)&stat.st_ctime, sizeof(SceDateTime));
memcpy(&entry->mtime, (SceDateTime *)&stat.st_mtime, sizeof(SceDateTime));
memcpy(&entry->atime, (SceDateTime *)&stat.st_atime, sizeof(SceDateTime));
memcpy(&entry->ctime, (SceDateTime *) &stat.st_ctime, sizeof(SceDateTime));
memcpy(&entry->mtime, (SceDateTime *) &stat.st_mtime, sizeof(SceDateTime));
memcpy(&entry->atime, (SceDateTime *) &stat.st_atime, sizeof(SceDateTime));
fileListAddEntry(list, entry, SORT_BY_NAME);
@ -1011,6 +1014,7 @@ int fileListGetDirectoryEntries(FileList *list, const char *path, int sort) {
strcpy(entry->name, DIR_UP);
entry->is_folder = 1;
entry->type = FILE_TYPE_UNKNOWN;
entry->is_symlink = 0;
fileListAddEntry(list, entry, sort);
}
@ -1025,6 +1029,9 @@ int fileListGetDirectoryEntries(FileList *list, const char *path, int sort) {
FileListEntry *entry = malloc(sizeof(FileListEntry));
if (entry) {
entry->is_folder = SCE_S_ISDIR(dir.d_stat.st_mode);
entry->is_symlink = 0;
entry->symlink = NULL;
if (entry->is_folder) {
entry->name_length = strlen(dir.d_name) + 1;
entry->name = malloc(entry->name_length + 1);
@ -1038,13 +1045,34 @@ int fileListGetDirectoryEntries(FileList *list, const char *path, int sort) {
strcpy(entry->name, dir.d_name);
entry->type = getFileType(entry->name);
list->files++;
if (dir.d_stat.st_size <= SYMLINK_MAX_SIZE) {
char *p = malloc(strlen(path) + strlen(dir.d_name) + 2);
if (!p) {
return VITASHELL_ERROR_INTERNAL;
}
snprintf(p, MAX_PATH_LENGTH - 1, "%s%s%s",
path, hasEndSlash(path) ? "" : "/", dir.d_name);
Symlink* symlink = malloc(sizeof(Symlink));
if (!symlink) {
return VITASHELL_ERROR_INTERNAL;
}
int res = resolveSimLink(symlink, p);
if (res < 0) {
if (symlink)
free(symlink);
} else {
entry->is_symlink = 1;
entry->symlink = symlink;
}
free(p);
}
}
entry->size = dir.d_stat.st_size;
memcpy(&entry->ctime, (SceDateTime *)&dir.d_stat.st_ctime, sizeof(SceDateTime));
memcpy(&entry->mtime, (SceDateTime *)&dir.d_stat.st_mtime, sizeof(SceDateTime));
memcpy(&entry->atime, (SceDateTime *)&dir.d_stat.st_atime, sizeof(SceDateTime));
memcpy(&entry->ctime, (SceDateTime *) &dir.d_stat.st_ctime, sizeof(SceDateTime));
memcpy(&entry->mtime, (SceDateTime *) &dir.d_stat.st_mtime, sizeof(SceDateTime));
memcpy(&entry->atime, (SceDateTime *) &dir.d_stat.st_atime, sizeof(SceDateTime));
fileListAddEntry(list, entry, sort);
}
@ -1070,3 +1098,107 @@ int fileListGetEntries(FileList *list, const char *path, int sort) {
return fileListGetDirectoryEntries(list, path, sort);
}
// returns < 0 on error
int resolveSimLink(Symlink *symlink, const char *path) {
SceUID fd = sceIoOpen(path, SCE_O_RDONLY, 0);
if (fd < 0)
return VITASHELL_ERROR_SYMLINK_INTERNAL;
char magic[SYMLINK_HEADER_SIZE + 1];
magic[SYMLINK_HEADER_SIZE] = '\0';
if (sceIoRead(fd, &magic, SYMLINK_HEADER_SIZE) < SYMLINK_HEADER_SIZE) {
sceIoClose(fd);
return VITASHELL_ERROR_SYMLINK_INTERNAL;
}
if(memcmp(magic, symlink_header_bytes, SYMLINK_HEADER_SIZE) != 0) {
sceIoClose(fd);
return VITASHELL_ERROR_SYMLINK_INTERNAL;
}
char *resolve = (char *) malloc(MAX_PATH_LENGTH);
if (!resolve) {
sceIoClose(fd);
return VITASHELL_ERROR_INTERNAL;
}
int bytes_read = sceIoRead(fd, resolve, MAX_PATH_LENGTH - 1);
sceIoClose(fd);
if (bytes_read <= 0) {
free(resolve);
return VITASHELL_ERROR_SYMLINK_INTERNAL;
}
resolve[bytes_read] = '\0';
SceIoStat io_stat;
memset(&io_stat, 0, sizeof(SceIoStat));
if (sceIoGetstat(resolve, &io_stat) < 0) {
free(resolve);
return VITASHELL_ERROR_SYMLINK_INTERNAL;
}
symlink->to_file = !SCE_S_ISDIR(io_stat.st_mode);
symlink->target_path = resolve;
symlink->target_path_length = bytes_read + 1;
return 0;
}
// return < 0 on error
int createSymLink(const char *store_location, const char *target) {
SceUID fd = sceIoOpen(store_location, SCE_O_WRONLY | SCE_O_CREAT, 0777);
if (fd < 0) {
return VITASHELL_ERROR_SYMLINK_INTERNAL;
}
sceIoWrite(fd, (void*) &symlink_header_bytes, SYMLINK_HEADER_SIZE);
sceIoWrite(fd, (void*) target, strnlen(target, MAX_PATH_LENGTH));
sceIoClose(fd);
return 0;
}
// get directory path from filename
// result has slash at the end
char * getBaseDirectory(const char * path) {
int i;
int sep_ind = -1;
int len = strlen(path);
if (len > MAX_PATH_LENGTH - 1 || len <= 0) return NULL;
for(i = len - 1; i >=0; i --) {
if (path[i] == '/' || path[i] == ':') {
sep_ind = i;
break;
}
}
if (sep_ind == -1) return NULL;
char * res = (char *) malloc(MAX_PATH_LENGTH);
if (!res) return NULL;
strncpy(res, path, MAX_PATH_LENGTH);
res[sep_ind + 1] = '\0';
return res;
}
// returns NULL when no filename found or error
// result is at most MAX_PATH_LEN
char * getFilename(const char *path) {
int i;
int sep_ind = -1;
int len = strlen(path);
if (len > MAX_PATH_LENGTH || len <= 0) return NULL;
if (path[len - 1] == '/' || path[len - 1] == ':') return NULL; // no file
for(i = len - 1; i >=0; i --) {
if (path[i] == '/' || path[i] == ':') {
sep_ind = i;
break;
}
}
if (sep_ind == -1) return NULL;
char * res = (char *) malloc(MAX_PATH_LENGTH);
if (!res) return NULL;
int new_len = len - (sep_ind + 1);
strncpy(res, path + (sep_ind + 1), new_len); // dont copy separation char
if (new_len + 1 < MAX_PATH_LENGTH)
res[new_len] = '\0';
else
res[MAX_PATH_LENGTH - 1] = '\0';
return res;
}

21
file.h
View File

@ -34,6 +34,12 @@
#define HOME_PATH "home"
#define DIR_UP ".."
#define SYMLINK_HEADER_SIZE 4
#define SYMLINK_MAX_SIZE (SYMLINK_HEADER_SIZE + MAX_PATH_LENGTH)
#define SYMLINK_EXT "lnk"
extern const char symlink_header_bytes[SYMLINK_HEADER_SIZE];
enum FileTypes {
FILE_TYPE_UNKNOWN,
FILE_TYPE_ARCHIVE,
@ -63,6 +69,12 @@ enum FileMoveFlags {
MOVE_REPLACE = 0x2, // Replace files
};
typedef struct {
int to_file; // 1: to file, 0: to directory
char *target_path;
int target_path_length;
} Symlink;
typedef struct {
uint64_t *value;
uint64_t max;
@ -77,6 +89,8 @@ typedef struct FileListEntry {
int name_length;
int is_folder;
int type;
int is_symlink;
Symlink *symlink;
SceOff size;
SceOff size2;
SceDateTime ctime;
@ -101,6 +115,10 @@ int WriteFile(const char *file, const void *buf, int size);
int checkFileExist(const char *file);
int checkFolderExist(const char *folder);
char * getBaseDirectory(const char *path);
char * getFilename(const char *path);
int getFileSize(const char *file);
int getFileSha1(const char *file, uint8_t *pSha1Out, FileProcessParam *param);
int getPathInfo(const char *path, uint64_t *size, uint32_t *folders, uint32_t *files, int (* handler)(const char *path));
@ -127,4 +145,7 @@ void fileListEmpty(FileList *list);
int fileListGetEntries(FileList *list, const char *path, int sort);
int resolveSimLink(Symlink* symlink, const char *target);
int createSymLink(const char *source_location, const char *target);
#endif

25
init.c
View File

@ -48,6 +48,8 @@ INCLUDE_EXTERN_RESOURCE(default_pause_png);
INCLUDE_EXTERN_RESOURCE(default_play_png);
INCLUDE_EXTERN_RESOURCE(default_sfo_icon_png);
INCLUDE_EXTERN_RESOURCE(default_text_icon_png);
INCLUDE_EXTERN_RESOURCE(default_file_symlink_icon_png);
INCLUDE_EXTERN_RESOURCE(default_folder_symlink_icon_png);
INCLUDE_EXTERN_RESOURCE(electron_colors_txt);
INCLUDE_EXTERN_RESOURCE(electron_archive_icon_png);
@ -106,7 +108,9 @@ static DefaultFile default_files[] = {
DEFAULT_FILE("ux0:VitaShell/theme/Default/fastforward.png", default_fastforward_png, 1),
DEFAULT_FILE("ux0:VitaShell/theme/Default/fastrewind.png", default_fastrewind_png, 1),
DEFAULT_FILE("ux0:VitaShell/theme/Default/file_icon.png", default_file_icon_png, 1),
DEFAULT_FILE("ux0:VitaShell/theme/Default/file_symlink_icon.png",default_file_symlink_icon_png, 1),
DEFAULT_FILE("ux0:VitaShell/theme/Default/folder_icon.png", default_folder_icon_png, 1),
DEFAULT_FILE("ux0:VitaShell/theme/Default/folder_symlink_icon.png",default_folder_symlink_icon_png, 1),
DEFAULT_FILE("ux0:VitaShell/theme/Default/ftp.png", default_ftp_png, 1),
DEFAULT_FILE("ux0:VitaShell/theme/Default/image_icon.png", default_image_icon_png, 1),
DEFAULT_FILE("ux0:VitaShell/theme/Default/pause.png", default_pause_png, 1),
@ -391,6 +395,27 @@ void initVitaShell() {
taiStopUnloadKernelModule(kernel_modid, 0, NULL, 0, NULL, NULL);
}
user_modid = sceKernelLoadStartModule("ux0:VitaShell/module/user.suprx", 0, NULL, 0, NULL, NULL);
// clear up recent folder frequently
SceIoStat stat;
SceDateTime now;
sceRtcGetCurrentClock(&now, 0);
int res = sceIoGetstat(VITASHELL_RECENT_PATH, &stat);
if (res >= 0) {
if (now.year * 365 + now.day - stat.st_ctime.year * 365 - stat.st_ctime.day
>= VITASHELL_RECENT_PATH_DELETE_INTERVAL_DAYS) {
removePath(VITASHELL_RECENT_PATH, 0);
}
}
if (!checkFolderExist(VITASHELL_BOOKMARKS_PATH)) {
sceIoMkdir(VITASHELL_BOOKMARKS_PATH, 0777);
}
if (!checkFolderExist(VITASHELL_RECENT_PATH)) {
sceIoMkdir(VITASHELL_RECENT_PATH, 0777);
}
time_last_recent_files = 0;
time_last_bookmars = 0;
}
void finishVitaShell() {

View File

@ -132,6 +132,11 @@ void loadLanguage(int id) {
LANGUAGE_ENTRY(SEND),
LANGUAGE_ENTRY(RECEIVE),
LANGUAGE_ENTRY(MORE),
LANGUAGE_ENTRY(BOOKMARKS),
LANGUAGE_ENTRY(ADHOC_TRANSFER),
LANGUAGE_ENTRY(BOOKMARKS_SHOW),
LANGUAGE_ENTRY(BOOKMARKS_NEW),
LANGUAGE_ENTRY(RECENT_FILES_SHOW),
LANGUAGE_ENTRY(COMPRESS),
LANGUAGE_ENTRY(INSTALL_ALL),
LANGUAGE_ENTRY(INSTALL_FOLDER),
@ -276,6 +281,7 @@ void loadLanguage(int id) {
LANGUAGE_ENTRY(ARCHIVE_NAME),
LANGUAGE_ENTRY(COMPRESSION_LEVEL),
LANGUAGE_ENTRY(ENTER_PASSWORD),
LANGUAGE_ENTRY(BOOKMARK_CREATED)
};
// Load default config file

View File

@ -91,6 +91,11 @@ enum LanguageContainer {
SEND,
RECEIVE,
MORE,
ADHOC_TRANSFER,
BOOKMARKS,
BOOKMARKS_SHOW,
BOOKMARKS_NEW,
RECENT_FILES_SHOW,
COMPRESS,
INSTALL_ALL,
INSTALL_FOLDER,
@ -235,6 +240,7 @@ enum LanguageContainer {
ARCHIVE_NAME,
COMPRESSION_LEVEL,
ENTER_PASSWORD,
BOOKMARK_CREATED,
LANGUAGE_CONTAINER_SIZE,
};

389
main.c
View File

@ -70,6 +70,7 @@ static int dir_level = 0;
// Modes
int sort_mode = SORT_BY_NAME;
int last_set_sort_mode = SORT_BY_NAME;
int copy_mode = COPY_MODE_NORMAL;
int file_type = FILE_TYPE_UNKNOWN;
@ -96,6 +97,44 @@ int SCE_CTRL_ENTER = SCE_CTRL_CROSS, SCE_CTRL_CANCEL = SCE_CTRL_CIRCLE;
// Use custom config
int use_custom_config = 1;
SceInt64 time_last_recent_files, time_last_bookmars;
static void setFocusOnFilename(const char *name);
static void fileBrowserHandleSymlink(FileListEntry* file_entry);
static void fileBrowserHandleFolder(FileListEntry* file_entry);
static void fileBrowserHandleFile(FileListEntry* file_entry);
static void create_recent_symlink(FileListEntry *file_entry);
static void delete_all_symlink_directory_path();
// escape from dir hierarchy with a symlink
typedef struct SymlinkDirectoryPath {
struct SymlinkDirectoryPath* previous;
// contains / at the end, is directory where jumped from
char last_path[MAX_PATH_LENGTH];
// contains / at the end, is directory where jumped to
char last_hook[MAX_PATH_LENGTH];
} SymlinkDirectoryPath;
static SymlinkDirectoryPath* symlink_directory_path = NULL;
static SymlinkDirectoryPath* symlink_directory_path_head = NULL;
static void storeSymlinkPath(SymlinkDirectoryPath * path) {
if (!symlink_directory_path) {
symlink_directory_path = path;
symlink_directory_path_head = path;
symlink_directory_path->previous = 0;
} else {
SymlinkDirectoryPath *prev = symlink_directory_path;
symlink_directory_path = path;
symlink_directory_path->previous = prev;
}
}
static void delete_all_symlink_directory_path() {
}
int getDialogStep() {
sceKernelLockLwMutex(&dialog_mutex, 1, NULL);
@ -132,6 +171,45 @@ void dirUpCloseArchive() {
}
}
int change_to_directory(char *lastdir) {
if (!checkFolderExist(lastdir)) {
return VITASHELL_ERROR_NAVIGATION;
} else {
if (isInArchive()) {
dirUpCloseArchive();
}
int i;
for (i = 0; i < strlen(lastdir) + 1; i++) {
if (lastdir[i] == ':' || lastdir[i] == '/') {
char ch = lastdir[i + 1];
lastdir[i + 1] = '\0';
char ch2 = lastdir[i];
lastdir[i] = '\0';
char *p = strrchr(lastdir, '/');
if (!p)
p = strrchr(lastdir, ':');
if (!p)
p = lastdir - 1;
lastdir[i] = ch2;
refreshFileList();
setFocusOnFilename(p + 1);
strcpy(file_list.path, lastdir);
lastdir[i + 1] = ch;
dirLevelUp();
}
}
}
refreshFileList();
return 0;
}
static void dirUp() {
if (pfs_mounted_path[0] &&
strcmp(file_list.path, pfs_mounted_path) == 0 && // we're about to leave the pfs path
@ -140,10 +218,36 @@ static void dirUp() {
pfsUmount();
}
// skip all symlink hierarchies when pressing O in bookmarks/ recent files
if (symlink_directory_path_head &&
((strncmp(file_list.path, VITASHELL_BOOKMARKS_PATH, MAX_PATH_LENGTH) == 0)
|| strncmp(file_list.path, VITASHELL_RECENT_PATH, MAX_PATH_LENGTH) == 0)) {
strcpy(file_list.path, symlink_directory_path_head->last_path);
SymlinkDirectoryPath *e = symlink_directory_path;
while(e != NULL) {
SymlinkDirectoryPath *prev = e->previous;
free(e);
dir_level--;
e = prev;
}
symlink_directory_path_head = 0;
symlink_directory_path = 0;
goto DIR_UP_RETURN;
}
if (symlink_directory_path
&& strncmp(file_list.path, symlink_directory_path->last_hook, MAX_PATH_LENGTH) == 0) {
strcpy(file_list.path, symlink_directory_path->last_path);
SymlinkDirectoryPath* prev = symlink_directory_path->previous;
free(symlink_directory_path);
symlink_directory_path = prev;
dir_level--;
goto DIR_UP_RETURN;
}
removeEndSlash(file_list.path);
char *p;
p = strrchr(file_list.path, '/');
if (p) {
p[1] = '\0';
@ -188,6 +292,14 @@ static void setFocusOnFilename(const char *name) {
int refreshFileList() {
int ret = 0, res = 0;
// always sort recent files by date
char *contains = strstr(file_list.path, VITASHELL_RECENT_PATH);
if (contains) {
sort_mode = SORT_BY_DATE;
} else {
sort_mode = last_set_sort_mode;
}
do {
fileListEmpty(&file_list);
@ -1491,21 +1603,24 @@ static int fileBrowserMenuCtrl() {
// SELECT button
if (pressed_pad[PAD_SELECT]) {
if (vitashell_config.select_button == SELECT_BUTTON_MODE_USB && sceKernelGetModel() == SCE_KERNEL_MODEL_VITA) {
if (vitashell_config.select_button == SELECT_BUTTON_MODE_USB &&
sceKernelGetModel() == SCE_KERNEL_MODEL_VITA) {
if (is_safe_mode) {
infoDialog(language_container[EXTENDED_PERMISSIONS_REQUIRED]);
} else {
SceUdcdDeviceState state;
sceUdcdGetDeviceState(&state);
if (state.cable & SCE_UDCD_STATUS_CABLE_CONNECTED) {
initUsb();
} else {
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL, language_container[USB_NOT_CONNECTED]);
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_CANCEL,
language_container[USB_NOT_CONNECTED]);
setDialogStep(DIALOG_STEP_USB_WAIT);
}
}
} else if (vitashell_config.select_button == SELECT_BUTTON_MODE_FTP || sceKernelGetModel() == SCE_KERNEL_MODEL_VITATV) {
} else if (vitashell_config.select_button == SELECT_BUTTON_MODE_FTP ||
sceKernelGetModel() == SCE_KERNEL_MODEL_VITATV) {
// Init FTP
if (!ftpvita_is_initialized()) {
int res = ftpvita_init(vita_ip, &vita_port);
@ -1522,11 +1637,13 @@ static int fileBrowserMenuCtrl() {
// Dialog
if (ftpvita_is_initialized()) {
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK_CANCEL, language_container[FTP_SERVER], vita_ip, vita_port);
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_OK_CANCEL, language_container[FTP_SERVER],
vita_ip, vita_port);
setDialogStep(DIALOG_STEP_FTP);
}
}
}
/*
// QR
if (hold_pad[PAD_LTRIGGER] && hold_pad[PAD_RTRIGGER] && enabledQR()) {
@ -1535,10 +1652,43 @@ static int fileBrowserMenuCtrl() {
setDialogStep(DIALOG_STEP_QR);
}
*/
// Move
// bookmarks shortcut
if (current_pad[PAD_LEFT] && current_pad[PAD_SQUARE]) {
SceInt64 now = sceKernelGetSystemTimeWide();
// switching too quickly back and forth between recent and bookmarks
// causes VS to crash
if (now - time_last_bookmars > THRESHOLD_LAST_PAD_BOOKMARKS_WAIT) {
if (strncmp(file_list.path, VITASHELL_BOOKMARKS_PATH, MAX_PATH_LENGTH) != 0) {
char path[MAX_PATH_LENGTH] = VITASHELL_BOOKMARKS_PATH;
sort_mode = last_set_sort_mode;
jump_to_directory_track_current_path(path);
time_last_bookmars = now;
return 0;
}
}
}
// recent files shortcut
if (current_pad[PAD_LEFT] && current_pad[PAD_TRIANGLE]) {
SceInt64 now = sceKernelGetSystemTimeWide();
if (now - time_last_recent_files > THRESHOLD_LAST_PAD_RECENT_FILES_WAIT) {
if (strncmp(file_list.path, VITASHELL_RECENT_PATH, MAX_PATH_LENGTH) != 0) {
char path[MAX_PATH_LENGTH] = VITASHELL_RECENT_PATH;
sort_mode = SORT_BY_DATE;
jump_to_directory_track_current_path(path);
time_last_recent_files = now;
return 0;
}
}
}
// Move
if (hold_pad[PAD_UP] || hold2_pad[PAD_LEFT_ANALOG_UP]) {
int old_pos = base_pos + rel_pos;
if (rel_pos > 0) {
rel_pos--;
} else if (base_pos > 0) {
@ -1632,55 +1782,135 @@ static int fileBrowserMenuCtrl() {
fileListEmpty(&mark_list);
// Handle file or folder
// Handle file, symlink or folder
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
if (file_entry) {
if (file_entry->is_folder) {
if (strcmp(file_entry->name, DIR_UP) == 0) {
dirUp();
} else {
if (dir_level == 0) {
strcpy(file_list.path, file_entry->name);
} else {
if (dir_level > 1)
addEndSlash(file_list.path);
strcat(file_list.path, file_entry->name);
}
dirLevelUp();
}
// Save last dir
WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1);
// Open folder
int res = refreshFileList();
if (res < 0)
errorDialog(res);
if (file_entry->is_symlink) {
fileBrowserHandleSymlink(file_entry);
} else if (file_entry->is_folder) {
fileBrowserHandleFolder(file_entry);
} else {
snprintf(cur_file, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name);
int type = handleFile(cur_file, file_entry);
// Archive mode
if (type == FILE_TYPE_ARCHIVE && getDialogStep() != DIALOG_STEP_ENTER_PASSWORD) {
is_in_archive = 1;
dir_level_archive = dir_level;
snprintf(archive_path, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name);
strcat(file_list.path, file_entry->name);
addEndSlash(file_list.path);
dirLevelUp();
refreshFileList();
}
fileBrowserHandleFile(file_entry);
create_recent_symlink(file_entry);
}
}
}
return refresh;
}
static void create_recent_symlink(FileListEntry *file_entry) {
char target[MAX_PATH_LENGTH];
snprintf(target, MAX_PATH_LENGTH, "%s%s."SYMLINK_EXT, VITASHELL_RECENT_PATH,
file_entry->name);
snprintf(cur_file, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name);
// create file recent symlink
createSymLink(target, cur_file);
}
static void fileBrowserHandleFile(FileListEntry *file_entry) {
snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
int type = handleFile(cur_file, file_entry);
// Archive mode
if (type == FILE_TYPE_ARCHIVE && getDialogStep() != DIALOG_STEP_ENTER_PASSWORD) {
is_in_archive = 1;
dir_level_archive = dir_level;
snprintf(archive_path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
strcat(file_list.path, file_entry->name);
addEndSlash(file_list.path);
dirLevelUp();
refreshFileList();
}
}
static void fileBrowserHandleFolder(FileListEntry *file_entry) {
if (strcmp(file_entry->name, DIR_UP) == 0) {
dirUp();
} else {
if (dir_level == 0) {
strcpy(file_list.path, file_entry->name);
} else {
if (dir_level > 1)
addEndSlash(file_list.path);
strcat(file_list.path, file_entry->name);
}
dirLevelUp();
}
// Save last dir
WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1);
// Open folder
int res = refreshFileList();
if (res < 0)
errorDialog(res);
}
// escape from dir level structure so that parent directory is browsed
// where this jump came from and not the hierarchically higher folder
int jump_to_directory_track_current_path(char *path) {
SymlinkDirectoryPath *symlink_path = malloc(sizeof(SymlinkDirectoryPath));
if (symlink_path) {
strncpy(symlink_path->last_path, file_list.path, MAX_PATH_LENGTH);
strncpy(symlink_path->last_hook, path, MAX_PATH_LENGTH);
dirLevelUp();
int _dir_level = dir_level; // we escape from hierarchical dir level structure
if (change_to_directory(path) < 0) {
free(symlink_path);
return VITASHELL_ERROR_NAVIGATION;
}
WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1);
storeSymlinkPath(symlink_path);
dir_level = _dir_level;
refreshFileList();
}
return 0;
}
static void fileBrowserHandleSymlink(FileListEntry *file_entry) {
if ((file_entry->symlink->to_file == 1 && !checkFileExist(file_entry->symlink->target_path))
|| (file_entry->symlink->to_file == 0 && !checkFolderExist(file_entry->symlink->target_path))) {
// TODO: What if in archive?
snprintf(cur_file, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
textViewer(cur_file);
return;
}
if (file_entry->symlink->to_file == 0) {
if (jump_to_directory_track_current_path(file_entry->symlink->target_path) < 0) {
errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH);
}
} else {
char *target_base_directory = getBaseDirectory(file_entry->symlink->target_path);
if (!target_base_directory) {
errorDialog(VITASHELL_ERROR_SYMLINK_CANT_RESOLVE_BASEDIR);
return;
}
char *target_file_name = getFilename(file_entry->symlink->target_path);
if (!target_file_name) {
errorDialog(VITASHELL_ERROR_SYMLINK_CANT_RESOLVE_FILENAME);
return;
}
if (jump_to_directory_track_current_path(target_base_directory) < 0) {
errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH);
return;
}
FileListEntry *resolved_file_entry = fileListFindEntry(&file_list, target_file_name);
if (!resolved_file_entry) {
errorDialog(VITASHELL_ERROR_SYMLINK_INVALID_PATH);
return;
}
fileBrowserHandleFile(resolved_file_entry);
dirUp();
}
int res = refreshFileList();
if (res < 0)
errorDialog(res);
}
static int shellMain() {
// Position
memset(base_pos_list, 0, sizeof(base_pos_list));
@ -1703,37 +1933,7 @@ static int shellMain() {
// Last dir
char lastdir[MAX_PATH_LENGTH];
ReadFile(VITASHELL_LASTDIR, lastdir, sizeof(lastdir));
// Calculate dir positions if the dir is valid
if (checkFolderExist(lastdir)) {
int i;
for (i = 0; i < strlen(lastdir) + 1; i++) {
if (lastdir[i] == ':' || lastdir[i] == '/') {
char ch = lastdir[i + 1];
lastdir[i + 1] = '\0';
char ch2 = lastdir[i];
lastdir[i] = '\0';
char *p = strrchr(lastdir, '/');
if (!p)
p = strrchr(lastdir, ':');
if (!p)
p = lastdir - 1;
lastdir[i] = ch2;
refreshFileList();
setFocusOnFilename(p + 1);
strcpy(file_list.path, lastdir);
lastdir[i + 1] = ch;
dirLevelUp();
}
}
}
change_to_directory(lastdir);
}
// Refresh file list
@ -1774,7 +1974,6 @@ static int shellMain() {
pfsUmount(); // umount game data at resume
refresh = REFRESH_MODE_NORMAL;
}
if (refresh != REFRESH_MODE_NONE) {
// Refresh lists
refreshFileList();
@ -1802,9 +2001,17 @@ static int shellMain() {
float y = START_Y + (i * FONT_Y_SPACE);
vita2d_texture *icon = NULL;
if (file_entry->is_symlink) {
if (file_entry->symlink->to_file) {
color = FILE_SYMLINK_COLOR;
icon = file_symlink_icon;
} else {
color = FOLDER_SYMLINK_COLOR;
icon = folder_symlink_icon;
}
}
// Folder
if (file_entry->is_folder) {
else if (file_entry->is_folder) {
color = FOLDER_COLOR;
icon = folder_icon;
} else {
@ -1862,11 +2069,21 @@ static int shellMain() {
// Draw file name
vita2d_enable_clipping();
vita2d_set_clip_rectangle(FILE_X + 1.0f, y, FILE_X + 1.0f + MAX_NAME_WIDTH, y + FONT_Y_SPACE);
float x = FILE_X;
char file_name[MAX_PATH_LENGTH];
memset(file_name, 0, sizeof(MAX_PATH_LENGTH));
if (file_entry->is_symlink) {
snprintf(file_name, MAX_PATH_LENGTH, "%s → %s",
file_entry->name, file_entry->symlink->target_path);
} else {
strncpy(file_name, file_entry->name, file_entry->name_length + 1);
file_name[file_entry->name_length] = '\0';
}
if (i == rel_pos) {
int width = (int)pgf_text_width(file_entry->name);
int width = (int)pgf_text_width(file_name);
if (width >= MAX_NAME_WIDTH) {
if (scroll_count < 60) {
scroll_x = x;
@ -1885,7 +2102,7 @@ static int shellMain() {
}
}
pgf_draw_text(x, y, color, file_entry->name);
pgf_draw_text(x, y, color, file_name);
vita2d_disable_clipping();

13
main.h
View File

@ -60,6 +60,11 @@
#define VITASHELL_LASTDIR "ux0:VitaShell/internal/lastdir.txt"
// needs / at the end
#define VITASHELL_BOOKMARKS_PATH "ux0:VitaShell/bookmarks/"
#define VITASHELL_RECENT_PATH "ux0:VitaShell/recent/"
#define VITASHELL_RECENT_PATH_DELETE_INTERVAL_DAYS 14
#define VITASHELL_TITLEID "VITASHELL"
#define ALIGN(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
@ -254,6 +259,13 @@ extern char archive_path[MAX_PATH_LENGTH];
extern int base_pos, rel_pos;
extern int sort_mode, copy_mode;
extern int last_set_sort_mode;
// minimum time to pass before shortcutting to recent files/ bookmarks via L/R keys
extern SceInt64 time_last_recent_files, time_last_bookmars;
#define THRESHOLD_LAST_PAD_RECENT_FILES_WAIT 1000000
#define THRESHOLD_LAST_PAD_BOOKMARKS_WAIT 1000000
extern vita2d_pgf *font;
extern char font_size_cache[256];
@ -276,5 +288,6 @@ int isInArchive();
int refreshFileList();
void ftpvita_PROM(ftpvita_client_info_t *client);
int jump_to_directory_track_current_path(char *path);
#endif

View File

@ -77,8 +77,9 @@ enum MenuMainEntrys {
MENU_MAIN_ENTRY_PROPERTIES,
MENU_MAIN_ENTRY_SORT_BY,
MENU_MAIN_ENTRY_MORE,
MENU_MAIN_ENTRY_SEND,
MENU_MAIN_ENTRY_RECEIVE,
MENU_MAIN_ENTRY_ADHOC,
MENU_MAIN_ENTRY_BOOKMARKS,
};
MenuEntry menu_main_entries[] = {
@ -93,8 +94,9 @@ MenuEntry menu_main_entries[] = {
{ PROPERTIES, 11, 0, CTX_INVISIBLE },
{ SORT_BY, 13, CTX_FLAG_MORE, CTX_VISIBLE },
{ MORE, 14, CTX_FLAG_MORE, CTX_INVISIBLE },
{ SEND, 17, 0, CTX_INVISIBLE }, // CTX_FLAG_BARRIER
{ RECEIVE, 18, 0, CTX_INVISIBLE },
{ ADHOC_TRANSFER, 16, CTX_FLAG_MORE, CTX_INVISIBLE },
{ BOOKMARKS, 17, CTX_FLAG_MORE, CTX_INVISIBLE },
};
#define N_MENU_MAIN_ENTRIES (sizeof(menu_main_entries) / sizeof(MenuEntry))
@ -113,6 +115,30 @@ MenuEntry menu_sort_entries[] = {
#define N_MENU_SORT_ENTRIES (sizeof(menu_sort_entries) / sizeof(MenuEntry))
enum MenuBookmarksEntrys {
MENU_BOOKMARKS_SHOW_BOOKMARKS,
MENU_BOOKMARKS_RECENT_FILES
};
MenuEntry menu_bookmark_entries[] = {
{ BOOKMARKS_SHOW, 12, 0, CTX_INVISIBLE },
{ RECENT_FILES_SHOW, 13, 0, CTX_INVISIBLE },
};
#define N_MENU_BOOKMARK_ENTRIES (sizeof(menu_bookmark_entries) / sizeof(MenuEntry))
enum MenuAdhocEntrys {
MENU_ADHOC_SEND,
MENU_ADHOC_RECEIVE
};
MenuEntry menu_adhoc_entries[] = {
{ SEND, 12, 0, CTX_INVISIBLE },
{ RECEIVE, 13, 0, CTX_INVISIBLE },
};
#define N_MENU_ADHOC_ENTRIES (sizeof(menu_adhoc_entries) / sizeof(MenuEntry))
enum MenuMoreEntrys {
MENU_MORE_ENTRY_COMPRESS,
MENU_MORE_ENTRY_INSTALL_ALL,
@ -133,12 +159,14 @@ MenuEntry menu_more_entries[] = {
enum MenuNewEntrys {
MENU_NEW_FILE,
MENU_NEW_FOLDER
MENU_NEW_FOLDER,
MENU_NEW_BOOKMARK
};
MenuEntry menu_new_entries[] = {
{NEW_FILE, 10, 0, CTX_INVISIBLE},
{NEW_FOLDER, 11, 0, CTX_INVISIBLE}
{NEW_FOLDER, 11, 0, CTX_INVISIBLE},
{BOOKMARKS_NEW, 12, 0, CTX_INVISIBLE}
};
@ -148,6 +176,8 @@ static int contextMenuHomeEnterCallback(int sel, void *context);
static int contextMenuMainEnterCallback(int sel, void *context);
static int contextMenuSortEnterCallback(int sel, void *context);
static int contextMenuMoreEnterCallback(int sel, void *context);
static int contextMenuBookmarksEnterCallback(int sel, void *context);
static int contextMenuAdhocEnterCallback(int sel, void *context);
static int contextMenuNewEnterCallback(int sel, void *context);
ContextMenu context_menu_home = {
@ -186,6 +216,25 @@ ContextMenu context_menu_more = {
.sel = -1,
};
ContextMenu context_menu_bookmarks = {
.parent = &context_menu_main,
.entries = menu_bookmark_entries,
.n_entries = N_MENU_BOOKMARK_ENTRIES,
.max_width = 0.0f,
.callback = contextMenuBookmarksEnterCallback,
.sel = -1,
};
ContextMenu context_menu_adhoc = {
.parent = &context_menu_main,
.entries = menu_adhoc_entries,
.n_entries = N_MENU_ADHOC_ENTRIES,
.max_width = 0.0f,
.callback = contextMenuAdhocEnterCallback,
.sel = -1,
};
ContextMenu context_menu_new = {
.parent = &context_menu_main,
.entries = menu_new_entries,
@ -287,7 +336,8 @@ void initContextMenuWidth() {
// Main
for (i = 0; i < N_MENU_MAIN_ENTRIES; i++) {
context_menu_main.max_width = MAX(context_menu_main.max_width, pgf_text_width(language_container[menu_main_entries[i].name]));
context_menu_main.max_width = MAX(context_menu_main.max_width,
pgf_text_width(language_container[menu_main_entries[i].name]));
if (menu_main_entries[i].name == MARK_ALL) {
menu_main_entries[i].name = UNMARK_ALL;
@ -321,6 +371,26 @@ void initContextMenuWidth() {
}
context_menu_new.max_width += 2.0f * CONTEXT_MENU_MARGIN;
context_menu_new.max_width = MAX(context_menu_new.max_width, CONTEXT_MENU_MIN_WIDTH);
// bookmarks
for (i = 0; i < N_MENU_BOOKMARK_ENTRIES; i++) {
context_menu_bookmarks.max_width = MAX(context_menu_bookmarks.max_width, pgf_text_width
(language_container[menu_bookmark_entries[i].name]));
}
context_menu_bookmarks.max_width += 2.0f * CONTEXT_MENU_MARGIN;
context_menu_bookmarks.max_width = MAX(context_menu_bookmarks.max_width, CONTEXT_MENU_MIN_WIDTH);
// adhoc
for (i = 0; i < N_MENU_ADHOC_ENTRIES; i++) {
context_menu_adhoc.max_width = MAX(context_menu_adhoc.max_width, pgf_text_width
(language_container[menu_adhoc_entries[i].name]));
}
context_menu_adhoc.max_width += 2.0f * CONTEXT_MENU_MARGIN;
context_menu_adhoc.max_width = MAX(context_menu_adhoc.max_width, CONTEXT_MENU_MIN_WIDTH);
}
void setContextMenuHomeVisibilities() {
@ -415,8 +485,6 @@ void setContextMenuMainVisibilities() {
menu_main_entries[MENU_MAIN_ENTRY_DELETE].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_RENAME].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_PROPERTIES].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_SEND].visibility = CTX_INVISIBLE;
// menu_main_entries[MENU_MAIN_ENTRY_RECEIVE].flags = CTX_FLAG_BARRIER;
}
// Invisible 'Paste' if nothing is copied yet
@ -433,8 +501,6 @@ void setContextMenuMainVisibilities() {
menu_main_entries[MENU_MAIN_ENTRY_DELETE].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_RENAME].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_NEW].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_SEND].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_RECEIVE].visibility = CTX_INVISIBLE;
}
// Mark/Unmark all text
@ -472,6 +538,74 @@ void setContextMenuMainVisibilities() {
context_menu_main.sel = -1;
}
void setContextMenuBookmarksVisibilities() {
int i;
// All visible
for (i = 0; i < N_MENU_BOOKMARK_ENTRIES; i++) {
if (menu_bookmark_entries[i].visibility == CTX_INVISIBLE)
menu_bookmark_entries[i].visibility = CTX_VISIBLE;
}
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
if (!file_entry)
return;
if (strcmp(file_list.path, VITASHELL_BOOKMARKS_PATH) == 0) {
menu_bookmark_entries[MENU_BOOKMARKS_SHOW_BOOKMARKS].visibility = CTX_INVISIBLE;
}
if (strcmp(file_list.path, VITASHELL_RECENT_PATH) == 0) {
menu_bookmark_entries[MENU_BOOKMARKS_RECENT_FILES].visibility = CTX_INVISIBLE;
}
// Go to first entry
for (i = 0; i < N_MENU_BOOKMARK_ENTRIES; i++) {
if (menu_bookmark_entries[i].visibility == CTX_VISIBLE) {
context_menu_bookmarks.sel = i;
break;
}
}
if (i == N_MENU_BOOKMARK_ENTRIES)
context_menu_bookmarks.sel = -1;
}
void setContextMenuAdhocVisibilities() {
int i;
// All visible
for (i = 0; i < N_MENU_ADHOC_ENTRIES; i++) {
if (menu_adhoc_entries[i].visibility == CTX_INVISIBLE)
menu_adhoc_entries[i].visibility = CTX_VISIBLE;
}
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
if (!file_entry)
return;
// Invisble entries when on '..'
if (strcmp(file_entry->name, DIR_UP) == 0) {
menu_adhoc_entries[MENU_ADHOC_SEND].visibility = CTX_INVISIBLE;
// menu_adhoc_entries[MENU_ADHOC_RECEIVE].flags = CTX_FLAG_BARRIER;
}
// Invisible write operations in archives
// TODO: read-only mount points
if (isInArchive() || (pfs_mounted_path[0] && strstr(file_list.path, pfs_mounted_path) && read_only)) {
menu_adhoc_entries[MENU_ADHOC_SEND].visibility = CTX_INVISIBLE;
menu_adhoc_entries[MENU_ADHOC_RECEIVE].visibility = CTX_INVISIBLE;
}
// Go to first entry
for (i = 0; i < N_MENU_ADHOC_ENTRIES; i++) {
if (menu_adhoc_entries[i].visibility == CTX_VISIBLE) {
context_menu_adhoc.sel = i;
break;
}
}
if (i == N_MENU_ADHOC_ENTRIES)
context_menu_adhoc.sel = -1;
}
void setContextMenuSortVisibilities() {
int i;
@ -601,6 +735,21 @@ void setContextMenuNewVisibilities() {
}
}
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
if (file_entry) {
snprintf(cur_file, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name);
if (strncmp(cur_file, VITASHELL_BOOKMARKS_PATH, MAX_PATH_LENGTH) == 0) {
menu_new_entries[MENU_NEW_BOOKMARK].visibility = CTX_INVISIBLE;
}
// Invisble entries when on '..'
if (strcmp(file_entry->name, DIR_UP) == 0 || file_entry->is_symlink) {
menu_new_entries[MENU_NEW_BOOKMARK].visibility = CTX_INVISIBLE;
}
} else {
menu_new_entries[MENU_NEW_BOOKMARK].visibility = CTX_INVISIBLE;
}
if (i == N_MENU_NEW_ENTRIES)
context_menu_new.sel = -1;
}
@ -999,18 +1148,18 @@ static int contextMenuMainEnterCallback(int sel, void *context) {
return CONTEXT_MENU_MORE_OPENING;
}
case MENU_MAIN_ENTRY_SEND:
case MENU_MAIN_ENTRY_BOOKMARKS:
{
initNetCheckDialog(SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_JOIN, 60 * 1000 * 1000);
setDialogStep(DIALOG_STEP_ADHOC_SEND_NETCHECK);
break;
setContextMenu(&context_menu_bookmarks);
setContextMenuBookmarksVisibilities();
return CONTEXT_MENU_MORE_OPENING;
}
case MENU_MAIN_ENTRY_RECEIVE:
case MENU_MAIN_ENTRY_ADHOC:
{
initNetCheckDialog(SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_CONN, 0);
setDialogStep(DIALOG_STEP_ADHOC_RECEIVE_NETCHECK);
break;
setContextMenu(&context_menu_adhoc);
setContextMenuAdhocVisibilities();
return CONTEXT_MENU_MORE_OPENING;
}
}
@ -1032,11 +1181,47 @@ static int contextMenuSortEnterCallback(int sel, void *context) {
break;
}
last_set_sort_mode = sort_mode;
// Refresh list
refreshFileList();
return CONTEXT_MENU_CLOSING;
}
static int contextMenuBookmarksEnterCallback(int sel, void *context) {
switch (sel) {
case MENU_BOOKMARKS_SHOW_BOOKMARKS:
{
char path[MAX_PATH_LENGTH] = VITASHELL_BOOKMARKS_PATH;
jump_to_directory_track_current_path(path);
break;
}
case MENU_BOOKMARKS_RECENT_FILES:
{
char path[MAX_PATH_LENGTH] = VITASHELL_RECENT_PATH;
jump_to_directory_track_current_path(path);
break;
}
}
return CONTEXT_MENU_CLOSING;
}
static int contextMenuAdhocEnterCallback(int sel, void *context) {
switch(sel) {
case MENU_ADHOC_RECEIVE: {
initNetCheckDialog(SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_CONN, 0);
setDialogStep(DIALOG_STEP_ADHOC_RECEIVE_NETCHECK);
break;
};
case MENU_ADHOC_SEND : {
initNetCheckDialog(SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_JOIN, 60 * 1000 * 1000);
setDialogStep(DIALOG_STEP_ADHOC_SEND_NETCHECK);
}
break;
}
return CONTEXT_MENU_CLOSING;
}
static int contextMenuMoreEnterCallback(int sel, void *context) {
switch (sel) {
@ -1156,7 +1341,6 @@ static int contextMenuMoreEnterCallback(int sel, void *context) {
return CONTEXT_MENU_CLOSING;
}
static int contextMenuNewEnterCallback(int sel, void *context) {
switch (sel) {
case MENU_NEW_FILE: {
@ -1204,6 +1388,26 @@ static int contextMenuNewEnterCallback(int sel, void *context) {
MAX_NAME_LENGTH, SCE_IME_TYPE_BASIC_LATIN, 0, 0);
setDialogStep(DIALOG_STEP_NEW_FOLDER);
break;
};
case MENU_NEW_BOOKMARK: {
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
if (file_entry) {
snprintf(cur_file, MAX_PATH_LENGTH, "%s%s", file_list.path, file_entry->name);
char target[MAX_PATH_LENGTH];
char name[MAX_PATH_LENGTH];
strncpy(name, file_entry->name, MAX_PATH_LENGTH);
removeEndSlash(name);
snprintf(target, MAX_PATH_LENGTH, "%s%s."SYMLINK_EXT, VITASHELL_BOOKMARKS_PATH, name);
int res;
if ((res = createSymLink(target, cur_file)) < 0) {
errorDialog(res);
} else {
infoDialog(language_container[BOOKMARK_CREATED]);
}
} else {
errorDialog(-2);
}
break;
}
}
// Refresh list

View File

@ -35,6 +35,8 @@ void initContextMenuWidth();
void setContextMenuHomeVisibilities();
void setContextMenuMainVisibilities();
void setContextMenuSortVisibilities();
void setContextMenuBookmarksVisibilities();
void setContextMenuAdhocVisibilities();
void setContextMenuMoreVisibilities();
void setContextMenuNewVisibilities();

View File

@ -24,6 +24,8 @@ ARCHIVE_COLOR = 0xFF007FFF # Orange
SCROLL_BAR_COLOR = 0xFFFF7F00 # Azure
SCROLL_BAR_BG_COLOR = 0xFF7F7F7F # Gray
MARKED_COLOR = 0x4FFF7F00 # Azure with alpha
FILE_SYMLINK_COLOR = 0xFFFFFFFF # White
FOLDER_SYMLINK_COLOR = 0xFFFFFFFF # White
# Context menu colors
CONTEXT_MENU_TEXT_COLOR = 0xFFFFFFFF # White

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -81,6 +81,12 @@ EXPORT_MEDIA = "Export media"
CUT = "Cut"
INSERT_EMPTY_LINE = "Insert empty line"
SEARCH = "Search"
BOOKMARKS = "Bookmarks"
ADHOC_TRANSFER = "Adhoc"
BOOKMARKS_SHOW = "Show bookmarks"
BOOKMARKS_NEW = "New bookmark"
BOOKMARK_CREATED = "Bookmark added"
RECENT_FILES_SHOW = "Recent files"
# File browser properties strings
PROPERTY_NAME = "Name"

13
theme.c
View File

@ -34,7 +34,9 @@ INCLUDE_EXTERN_RESOURCE(default_cover_png);
INCLUDE_EXTERN_RESOURCE(default_fastforward_png);
INCLUDE_EXTERN_RESOURCE(default_fastrewind_png);
INCLUDE_EXTERN_RESOURCE(default_file_icon_png);
INCLUDE_EXTERN_RESOURCE(default_file_symlink_icon_png);
INCLUDE_EXTERN_RESOURCE(default_folder_icon_png);
INCLUDE_EXTERN_RESOURCE(default_folder_symlink_icon_png);
INCLUDE_EXTERN_RESOURCE(default_ftp_png);
INCLUDE_EXTERN_RESOURCE(default_image_icon_png);
INCLUDE_EXTERN_RESOURCE(default_pause_png);
@ -58,6 +60,8 @@ int SETTINGS_MENU_OPTION_COLOR;
// File browser colors
int FOCUS_COLOR;
int FILE_COLOR;
int FILE_SYMLINK_COLOR;
int FOLDER_SYMLINK_COLOR;
int SFO_COLOR;
int TXT_COLOR;
int FOLDER_COLOR;
@ -105,7 +109,8 @@ int AUDIO_TIME_TOTAL;
int AUDIO_TIME_BAR;
int AUDIO_TIME_BAR_BG;
vita2d_texture *folder_icon = NULL, *file_icon = NULL, *archive_icon = NULL, *image_icon = NULL, *audio_icon = NULL, *sfo_icon = NULL, *text_icon = NULL,
vita2d_texture *folder_icon = NULL, *folder_symlink_icon = NULL, *file_icon = NULL,*file_symlink_icon = NULL, *archive_icon =NULL, *image_icon = NULL,
*audio_icon = NULL, *sfo_icon = NULL, *text_icon = NULL,
*ftp_image = NULL, *dialog_image = NULL, *context_image = NULL, *context_more_image = NULL, *settings_image = NULL, *battery_image = NULL,
*battery_bar_red_image = NULL, *battery_bar_green_image = NULL, *battery_bar_charge_image = NULL, *bg_browser_image = NULL, *bg_hex_image = NULL, *bg_text_image = NULL,
*bg_photo_image = NULL, *bg_audio_image = NULL, *cover_image = NULL, *play_image = NULL, *pause_image = NULL, *fastforward_image = NULL, *fastrewind_image = NULL;
@ -142,7 +147,11 @@ ThemeImage theme_images[] = {
{ "fastforward.png", &_binary_resources_default_fastforward_png_start, &fastforward_image },
{ "fastrewind.png", &_binary_resources_default_fastrewind_png_start, &fastrewind_image },
{ "file_icon.png", &_binary_resources_default_file_icon_png_start, &file_icon },
{ "file_symlink_icon.png", &_binary_resources_default_file_symlink_icon_png_start,
&file_symlink_icon },
{ "folder_icon.png", &_binary_resources_default_folder_icon_png_start, &folder_icon },
{ "folder_symlink_icon.png", &_binary_resources_default_folder_symlink_icon_png_start,
&folder_symlink_icon },
{ "ftp.png", &_binary_resources_default_ftp_png_start, &ftp_image },
{ "image_icon.png", &_binary_resources_default_image_icon_png_start, &image_icon },
{ "pause.png", &_binary_resources_default_pause_png_start, &pause_image },
@ -174,6 +183,8 @@ void loadTheme() {
// File browser colors
COLOR_ENTRY(FOCUS_COLOR),
COLOR_ENTRY(FILE_COLOR),
COLOR_ENTRY(FILE_SYMLINK_COLOR),
COLOR_ENTRY(FOLDER_SYMLINK_COLOR),
COLOR_ENTRY(SFO_COLOR),
COLOR_ENTRY(TXT_COLOR),
COLOR_ENTRY(FOLDER_COLOR),

View File

@ -43,6 +43,8 @@ extern int ARCHIVE_COLOR;
extern int SCROLL_BAR_COLOR;
extern int SCROLL_BAR_BG_COLOR;
extern int MARKED_COLOR;
extern int FILE_SYMLINK_COLOR;
extern int FOLDER_SYMLINK_COLOR;
// Context menu colors
extern int CONTEXT_MENU_TEXT_COLOR;
@ -85,7 +87,8 @@ extern int AUDIO_TIME_BAR_BG;
extern vita2d_texture *folder_icon, *file_icon, *archive_icon, *image_icon, *audio_icon, *sfo_icon, *text_icon,
*ftp_image, *dialog_image, *context_image, *context_more_image, *settings_image, *battery_image,
*battery_bar_red_image, *battery_bar_green_image, *battery_bar_charge_image, *bg_browser_image, *bg_hex_image, *bg_text_image,
*bg_photo_image, *bg_audio_image, *cover_image, *play_image, *pause_image, *fastforward_image, *fastrewind_image;
*bg_photo_image, *bg_audio_image, *cover_image, *play_image, *pause_image,
*fastforward_image, *fastrewind_image, *folder_symlink_icon, *file_symlink_icon;
extern vita2d_texture *wallpaper_image;
extern vita2d_texture *previous_wallpaper_image, *current_wallpaper_image;

View File

@ -34,6 +34,17 @@ enum VitaShellErrors {
VITASHELL_ERROR_DST_IS_SUBFOLDER_OF_SRC = 0xF0020001,
VITASHELL_ERROR_INVALID_TITLEID = 0xF0030000,
VITASHELL_ERROR_SYMLINK_INVALID_PATH = 0xF0040000,
VITASHELL_ERROR_SYMLINK_CANT_RESOLVE_BASEDIR = 0xF0040001,
VITASHELL_ERROR_SYMLINK_CANT_RESOLVE_FILENAME = 0xF0040002,
VITASHELL_ERROR_SYMLINK_INTERNAL = 0xF0040003,
VITASHELL_ERROR_NAVIGATION = 0xF0050000,
};
#endif