Cloud/backup page, map+cloud buttons, drop SELECT sync menu
Search bar: add two right-side buttons (map placeholder, cloud) drawn as anti-aliased glyph masks; rework the magnifier into a thin ring + handle. Cloud button opens a Server & Backup page: server storage used/total with a usage bar, server version and URL, app version, and on-device image counts (detected / backed up / remaining), fetched lazily via /api/server/storage and /api/server/version (with server-info legacy fallback). A "See details" button opens a scrollable list of not-backed-up files with per-item status (waiting / hashing / uploading / failed). An "Upload all" button (and the detail counts) replace the removed sync screen. Remove the SELECT sync overview (MODE_SYNC) and its now-unused helpers; the upload-all action it hosted now lives on the cloud page so backups stay reachable.
This commit is contained in:
+452
-228
@@ -65,6 +65,7 @@
|
|||||||
|
|
||||||
#define PAGE_SIZE 100
|
#define PAGE_SIZE 100
|
||||||
#define DATELEN 20 /* "YYYY-MM-DDTHH:MM:SS" + NUL, sortable */
|
#define DATELEN 20 /* "YYYY-MM-DDTHH:MM:SS" + NUL, sortable */
|
||||||
|
#define APP_VERSION "1.0" /* keep in step with CMakeLists VITA_VERSION */
|
||||||
|
|
||||||
#define CONFIG_DIR "ux0:data/vitaimmich"
|
#define CONFIG_DIR "ux0:data/vitaimmich"
|
||||||
#define CONFIG_PATH CONFIG_DIR "/config.txt"
|
#define CONFIG_PATH CONFIG_DIR "/config.txt"
|
||||||
@@ -189,6 +190,14 @@ static int *g_search_idx;
|
|||||||
static int g_search_count;
|
static int g_search_count;
|
||||||
static int g_search_cap;
|
static int g_search_cap;
|
||||||
|
|
||||||
|
/* server info shown on the cloud/backup page; fetched lazily the first time
|
||||||
|
* the page is opened. g_srv_state: 0 not fetched, 1 ok, -1 failed. */
|
||||||
|
static int g_srv_state;
|
||||||
|
static char g_srv_use[40]; /* disk used, human ("1.4 TiB") */
|
||||||
|
static char g_srv_total[40]; /* disk size, human ("1.8 TiB") */
|
||||||
|
static int g_srv_pct; /* disk usage percentage */
|
||||||
|
static char g_srv_version[40]; /* "v1.119.0" */
|
||||||
|
|
||||||
/* Texture recycling pool. Freeing a texture unmaps its memblock, and the
|
/* Texture recycling pool. Freeing a texture unmaps its memblock, and the
|
||||||
* GPU side (notably Vita3K's texture cache, which re-reads guest memory of
|
* GPU side (notably Vita3K's texture cache, which re-reads guest memory of
|
||||||
* cached textures at its own pace) may still touch it afterwards — freeing
|
* cached textures at its own pace) may still touch it afterwards — freeing
|
||||||
@@ -724,6 +733,95 @@ static CURLcode http_request(const char *url, const char *body,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* copy the value of a top-level JSON key into `out` (raw token text, works
|
||||||
|
* for both string and number values). returns 1 if found. small flat
|
||||||
|
* responses only (server storage / version). */
|
||||||
|
static int json_get(const char *js, size_t len, const char *key,
|
||||||
|
char *out, size_t outlen)
|
||||||
|
{
|
||||||
|
jsmn_parser p;
|
||||||
|
jsmn_init(&p);
|
||||||
|
int n = jsmn_parse(&p, js, len, NULL, 0);
|
||||||
|
if (n <= 0)
|
||||||
|
return 0;
|
||||||
|
jsmntok_t *t = malloc(sizeof(*t) * n);
|
||||||
|
if (!t)
|
||||||
|
return 0;
|
||||||
|
jsmn_init(&p);
|
||||||
|
n = jsmn_parse(&p, js, len, t, n);
|
||||||
|
int kl = (int)strlen(key), got = 0;
|
||||||
|
for (int i = 1; i + 1 < n; i++) {
|
||||||
|
if (t[i].type == JSMN_STRING && t[i].parent == 0 &&
|
||||||
|
t[i].end - t[i].start == kl &&
|
||||||
|
!strncmp(js + t[i].start, key, kl)) {
|
||||||
|
int vl = t[i + 1].end - t[i + 1].start;
|
||||||
|
if (vl >= (int)outlen)
|
||||||
|
vl = (int)outlen - 1;
|
||||||
|
memcpy(out, js + t[i + 1].start, vl);
|
||||||
|
out[vl] = '\0';
|
||||||
|
got = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(t);
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GET a JSON endpoint, trying the modern path then a legacy fallback. fills
|
||||||
|
* `out`/`code`; caller frees out->data. returns CURLcode of the call used. */
|
||||||
|
static CURLcode server_get(const char *path, const char *legacy,
|
||||||
|
membuf *out, long *code)
|
||||||
|
{
|
||||||
|
char url[600];
|
||||||
|
snprintf(url, sizeof(url), "%s%s", g_server, path);
|
||||||
|
CURLcode r = http_request(url, NULL, out, code, NULL, 0);
|
||||||
|
if (r == CURLE_OK && (*code < 200 || *code >= 300) && legacy) {
|
||||||
|
free(out->data);
|
||||||
|
snprintf(url, sizeof(url), "%s%s", g_server, legacy);
|
||||||
|
r = http_request(url, NULL, out, code, NULL, 0);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fetch disk usage + server version into the g_srv_* fields (main thread) */
|
||||||
|
static void fetch_server_info(void)
|
||||||
|
{
|
||||||
|
membuf buf;
|
||||||
|
long code;
|
||||||
|
|
||||||
|
CURLcode r = server_get("/api/server/storage",
|
||||||
|
"/api/server-info/storage", &buf, &code);
|
||||||
|
if (r == CURLE_OK && code >= 200 && code < 300 && buf.data) {
|
||||||
|
char pct[24] = "";
|
||||||
|
if (!json_get(buf.data, buf.size, "diskUse",
|
||||||
|
g_srv_use, sizeof(g_srv_use)))
|
||||||
|
g_srv_use[0] = '\0';
|
||||||
|
if (!json_get(buf.data, buf.size, "diskSize",
|
||||||
|
g_srv_total, sizeof(g_srv_total)))
|
||||||
|
g_srv_total[0] = '\0';
|
||||||
|
if (json_get(buf.data, buf.size, "diskUsagePercentage",
|
||||||
|
pct, sizeof(pct)))
|
||||||
|
g_srv_pct = (int)(atof(pct) + 0.5);
|
||||||
|
g_srv_state = 1;
|
||||||
|
} else {
|
||||||
|
log_line("server storage: curl %d http %ld", r, code);
|
||||||
|
g_srv_state = -1;
|
||||||
|
}
|
||||||
|
free(buf.data);
|
||||||
|
|
||||||
|
r = server_get("/api/server/version", "/api/server-info/version",
|
||||||
|
&buf, &code);
|
||||||
|
if (r == CURLE_OK && code >= 200 && code < 300 && buf.data) {
|
||||||
|
char mj[12] = "", mn[12] = "", pt[12] = "";
|
||||||
|
json_get(buf.data, buf.size, "major", mj, sizeof(mj));
|
||||||
|
json_get(buf.data, buf.size, "minor", mn, sizeof(mn));
|
||||||
|
json_get(buf.data, buf.size, "patch", pt, sizeof(pt));
|
||||||
|
snprintf(g_srv_version, sizeof(g_srv_version), "v%s.%s.%s",
|
||||||
|
mj[0] ? mj : "?", mn[0] ? mn : "?", pt[0] ? pt : "?");
|
||||||
|
}
|
||||||
|
free(buf.data);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
/* JPEG decoding */
|
/* JPEG decoding */
|
||||||
/* */
|
/* */
|
||||||
@@ -1854,16 +1952,16 @@ static void draw_sel_outline(float x, float y, float w, float h)
|
|||||||
* texture's bilinear sampling are what soften the corners. */
|
* texture's bilinear sampling are what soften the corners. */
|
||||||
static vita2d_texture *rounded_mask_tex(int w, int h, float r)
|
static vita2d_texture *rounded_mask_tex(int w, int h, float r)
|
||||||
{
|
{
|
||||||
static vita2d_texture *cache;
|
enum { NSLOT = 6 }; /* a small fixed set of shapes (pill, buttons, ...) */
|
||||||
static int cw, ch;
|
static vita2d_texture *cache[NSLOT];
|
||||||
static float cr;
|
static int cw[NSLOT], ch[NSLOT];
|
||||||
if (cache && cw == w && ch == h && cr == r)
|
static float cr[NSLOT];
|
||||||
return cache;
|
static int n;
|
||||||
if (cache) {
|
for (int i = 0; i < n; i++)
|
||||||
vita2d_wait_rendering_done();
|
if (cw[i] == w && ch[i] == h && cr[i] == r)
|
||||||
vita2d_free_texture(cache);
|
return cache[i];
|
||||||
cache = NULL;
|
if (n >= NSLOT)
|
||||||
}
|
return NULL;
|
||||||
vita2d_texture *t = vita2d_create_empty_texture_format(w, h,
|
vita2d_texture *t = vita2d_create_empty_texture_format(w, h,
|
||||||
SCE_GXM_TEXTURE_FORMAT_A8B8G8R8);
|
SCE_GXM_TEXTURE_FORMAT_A8B8G8R8);
|
||||||
if (!t)
|
if (!t)
|
||||||
@@ -1892,27 +1990,85 @@ static vita2d_texture *rounded_mask_tex(int w, int h, float r)
|
|||||||
hits * 255 / 16);
|
hits * 255 / 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cache = t;
|
cache[n] = t;
|
||||||
cw = w;
|
cw[n] = w;
|
||||||
ch = h;
|
ch[n] = h;
|
||||||
cr = r;
|
cr[n] = r;
|
||||||
return cache;
|
n++;
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* a line-art magnifying glass baked into an AA white mask (4x4 supersampled):
|
/* ---- AA glyph icons (magnifier / map pin / cloud) -------------------- */
|
||||||
* a thin ring outline plus a straight, round-capped handle off the lower
|
/* each is a coverage predicate over icon-local pixel coords (0..s); bake_icon
|
||||||
* right. drawn tinted to the icon colour. cached at one size. */
|
* supersamples it 4x4 into a white alpha mask, drawn tinted to the wanted
|
||||||
static vita2d_texture *search_icon_tex(int s)
|
* colour. one cached texture per icon (called at a fixed size each frame). */
|
||||||
|
|
||||||
|
static float seg_dist(float px, float py, float ax, float ay,
|
||||||
|
float bx, float by)
|
||||||
{
|
{
|
||||||
static vita2d_texture *cache;
|
float dx = bx - ax, dy = by - ay;
|
||||||
static int cs;
|
float l2 = dx * dx + dy * dy;
|
||||||
if (cache && cs == s)
|
float t = l2 > 0 ? ((px - ax) * dx + (py - ay) * dy) / l2 : 0;
|
||||||
return cache;
|
if (t < 0) t = 0;
|
||||||
if (cache) {
|
if (t > 1) t = 1;
|
||||||
vita2d_wait_rendering_done();
|
float qx = ax + dx * t, qy = ay + dy * t;
|
||||||
vita2d_free_texture(cache);
|
return sqrtf((px - qx) * (px - qx) + (py - qy) * (py - qy));
|
||||||
cache = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int in_tri(float px, float py, float ax, float ay, float bx, float by,
|
||||||
|
float cx, float cy)
|
||||||
|
{
|
||||||
|
float d1 = (px - bx) * (ay - by) - (ax - bx) * (py - by);
|
||||||
|
float d2 = (px - cx) * (by - cy) - (bx - cx) * (py - cy);
|
||||||
|
float d3 = (px - ax) * (cy - ay) - (cx - ax) * (py - ay);
|
||||||
|
int neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
||||||
|
int pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
||||||
|
return !(neg && pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a thin ring outline with a straight, round-capped handle off the lower right */
|
||||||
|
static int cov_search(float px, float py, int s)
|
||||||
|
{
|
||||||
|
float R = s * 0.30f, W = s * 0.11f;
|
||||||
|
if (W < 1.8f) W = 1.8f;
|
||||||
|
float ccx = s * 0.40f, ccy = s * 0.40f, hw = W * 0.5f, c45 = 0.70710678f;
|
||||||
|
float dr = sqrtf((px - ccx) * (px - ccx) + (py - ccy) * (py - ccy));
|
||||||
|
int ring = (dr <= R && dr >= R - W);
|
||||||
|
float ax = ccx + c45 * (R - hw), ay = ccy + c45 * (R - hw);
|
||||||
|
float bx = ccx + c45 * (R + s * 0.42f), by = ccy + c45 * (R + s * 0.42f);
|
||||||
|
return ring || seg_dist(px, py, ax, ay, bx, by) <= hw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a filled map marker: a round head (with a hole) tapering to a point */
|
||||||
|
static int cov_map(float px, float py, int s)
|
||||||
|
{
|
||||||
|
float cx = s * 0.5f, hcy = s * 0.40f, Rp = s * 0.30f, tipY = s * 0.95f;
|
||||||
|
float dHead = sqrtf((px - cx) * (px - cx) + (py - hcy) * (py - hcy));
|
||||||
|
int solid = (dHead <= Rp) ||
|
||||||
|
in_tri(px, py, cx - Rp * 0.78f, hcy + Rp * 0.30f,
|
||||||
|
cx + Rp * 0.78f, hcy + Rp * 0.30f, cx, tipY);
|
||||||
|
return solid && dHead >= Rp * 0.42f; /* punch the hole */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a filled cloud: three lobes tangent to a flat bottom (rounded sides), with
|
||||||
|
* a small body rectangle filling between the side lobes. all kept well inside
|
||||||
|
* the icon bounds so nothing clips at the edge. */
|
||||||
|
static int cov_cloud(float px, float py, int s)
|
||||||
|
{
|
||||||
|
float yb = s * 0.68f; /* flat bottom */
|
||||||
|
int mid = sqrtf((px - s * 0.50f) * (px - s * 0.50f) +
|
||||||
|
(py - s * 0.42f) * (py - s * 0.42f)) <= s * 0.22f;
|
||||||
|
int lp = sqrtf((px - s * 0.34f) * (px - s * 0.34f) +
|
||||||
|
(py - s * 0.52f) * (py - s * 0.52f)) <= s * 0.16f;
|
||||||
|
int rp = sqrtf((px - s * 0.66f) * (px - s * 0.66f) +
|
||||||
|
(py - s * 0.52f) * (py - s * 0.52f)) <= s * 0.16f;
|
||||||
|
int base = (px >= s * 0.34f && px <= s * 0.66f &&
|
||||||
|
py >= s * 0.52f && py <= yb);
|
||||||
|
return mid || lp || rp || base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vita2d_texture *bake_icon(int s, int (*inside)(float, float, int))
|
||||||
|
{
|
||||||
vita2d_texture *t = vita2d_create_empty_texture_format(s, s,
|
vita2d_texture *t = vita2d_create_empty_texture_format(s, s,
|
||||||
SCE_GXM_TEXTURE_FORMAT_A8B8G8R8);
|
SCE_GXM_TEXTURE_FORMAT_A8B8G8R8);
|
||||||
if (!t)
|
if (!t)
|
||||||
@@ -1920,49 +2076,42 @@ static vita2d_texture *search_icon_tex(int s)
|
|||||||
uint32_t *data = vita2d_texture_get_datap(t);
|
uint32_t *data = vita2d_texture_get_datap(t);
|
||||||
int stride = (int)(vita2d_texture_get_stride(t) / 4);
|
int stride = (int)(vita2d_texture_get_stride(t) / 4);
|
||||||
memset(data, 0, (size_t)stride * s * 4);
|
memset(data, 0, (size_t)stride * s * 4);
|
||||||
|
for (int y = 0; y < s; y++)
|
||||||
float R = s * 0.30f; /* ring outer radius */
|
|
||||||
float W = s * 0.11f; /* stroke width */
|
|
||||||
if (W < 1.8f) W = 1.8f;
|
|
||||||
float ccx = s * 0.40f, ccy = s * 0.40f; /* ring centre */
|
|
||||||
float hw = W * 0.5f;
|
|
||||||
float c45 = 0.70710678f;
|
|
||||||
/* handle segment, 45 deg toward the lower-right corner */
|
|
||||||
float ax = ccx + c45 * (R - hw), ay = ccy + c45 * (R - hw);
|
|
||||||
float bx = ccx + c45 * (R + s * 0.42f), by = ccy + c45 * (R + s * 0.42f);
|
|
||||||
float seg2 = (bx - ax) * (bx - ax) + (by - ay) * (by - ay);
|
|
||||||
|
|
||||||
for (int y = 0; y < s; y++) {
|
|
||||||
for (int x = 0; x < s; x++) {
|
for (int x = 0; x < s; x++) {
|
||||||
int hits = 0;
|
int hits = 0;
|
||||||
for (int sy = 0; sy < 4; sy++)
|
for (int sy = 0; sy < 4; sy++)
|
||||||
for (int sx = 0; sx < 4; sx++) {
|
for (int sx = 0; sx < 4; sx++)
|
||||||
float px = x + (sx + 0.5f) / 4.0f;
|
hits += inside(x + (sx + 0.5f) / 4.0f,
|
||||||
float py = y + (sy + 0.5f) / 4.0f;
|
y + (sy + 0.5f) / 4.0f, s);
|
||||||
float dr = sqrtf((px - ccx) * (px - ccx) +
|
|
||||||
(py - ccy) * (py - ccy));
|
|
||||||
int in = (dr <= R && dr >= R - W);
|
|
||||||
/* distance to the handle segment */
|
|
||||||
float tt = seg2 > 0 ?
|
|
||||||
((px - ax) * (bx - ax) +
|
|
||||||
(py - ay) * (by - ay)) / seg2 : 0;
|
|
||||||
if (tt < 0) tt = 0;
|
|
||||||
if (tt > 1) tt = 1;
|
|
||||||
float hxp = ax + (bx - ax) * tt;
|
|
||||||
float hyp = ay + (by - ay) * tt;
|
|
||||||
float dh = sqrtf((px - hxp) * (px - hxp) +
|
|
||||||
(py - hyp) * (py - hyp));
|
|
||||||
if (in || dh <= hw)
|
|
||||||
hits++;
|
|
||||||
}
|
|
||||||
data[y * stride + x] = RGBA8(255, 255, 255,
|
data[y * stride + x] = RGBA8(255, 255, 255,
|
||||||
hits * 255 / 16);
|
hits * 255 / 16);
|
||||||
}
|
}
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
cache = t;
|
|
||||||
cs = s;
|
/* cache one texture per glyph; all are drawn at a fixed size each frame */
|
||||||
return cache;
|
static vita2d_texture *icon_tex(int which, int s)
|
||||||
|
{
|
||||||
|
static vita2d_texture *cache[3];
|
||||||
|
static int cs[3];
|
||||||
|
if (which < 0 || which > 2)
|
||||||
|
return NULL;
|
||||||
|
if (cache[which] && cs[which] == s)
|
||||||
|
return cache[which];
|
||||||
|
if (cache[which]) {
|
||||||
|
vita2d_wait_rendering_done();
|
||||||
|
vita2d_free_texture(cache[which]);
|
||||||
|
cache[which] = NULL;
|
||||||
}
|
}
|
||||||
|
int (*fn)(float, float, int) = which == 0 ? cov_search :
|
||||||
|
which == 1 ? cov_map : cov_cloud;
|
||||||
|
cache[which] = bake_icon(s, fn);
|
||||||
|
cs[which] = s;
|
||||||
|
return cache[which];
|
||||||
|
}
|
||||||
|
#define ICON_SEARCH 0
|
||||||
|
#define ICON_MAP 1
|
||||||
|
#define ICON_CLOUD 2
|
||||||
|
|
||||||
/* small clear (x) chip used on the right of the bar while a search is on */
|
/* small clear (x) chip used on the right of the bar while a search is on */
|
||||||
static void draw_clear_x(float cx, float cy, float s, unsigned int col)
|
static void draw_clear_x(float cx, float cy, float s, unsigned int col)
|
||||||
@@ -1973,14 +2122,34 @@ static void draw_clear_x(float cx, float cy, float s, unsigned int col)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pixel geometry of the search pill, shared by the drawer and the tap test */
|
/* pixel geometry of the search pill + the two buttons on its right, shared
|
||||||
|
* by the drawer and the tap test */
|
||||||
#define BAR_M 12.0f /* left/right margin */
|
#define BAR_M 12.0f /* left/right margin */
|
||||||
#define BAR_Y 8.0f /* top of the pill */
|
#define BAR_Y 8.0f /* top of the pill */
|
||||||
#define BAR_H 40.0f /* pill height */
|
#define BAR_H 40.0f /* pill height */
|
||||||
#define BAR_R 12.0f /* corner radius */
|
#define BAR_R 12.0f /* corner radius */
|
||||||
#define BAR_W ((float)SCREEN_W - 2 * BAR_M)
|
#define BTN_SZ 40.0f /* button (rounded square) size */
|
||||||
|
#define BTN_GAP 10.0f /* gap between the two buttons */
|
||||||
|
#define BTN2_CX ((float)SCREEN_W - BAR_M - BTN_SZ / 2) /* cloud (rightmost) */
|
||||||
|
#define BTN1_CX (BTN2_CX - BTN_SZ - BTN_GAP) /* map */
|
||||||
|
#define BTN_CY (BAR_Y + BAR_H / 2)
|
||||||
|
#define BAR_W (BTN1_CX - BTN_SZ / 2 - BTN_GAP - BAR_M) /* pill width */
|
||||||
#define BAR_CLEAR_CX (BAR_M + BAR_W - 22.0f) /* centre of the clear chip */
|
#define BAR_CLEAR_CX (BAR_M + BAR_W - 22.0f) /* centre of the clear chip */
|
||||||
|
|
||||||
|
/* one future-feature button: rounded-square background + a centred AA glyph */
|
||||||
|
static void draw_bar_button(float cx, int icon)
|
||||||
|
{
|
||||||
|
vita2d_texture *bg = rounded_mask_tex((int)BTN_SZ, (int)BTN_SZ, 11.0f);
|
||||||
|
if (bg)
|
||||||
|
vita2d_draw_texture_tint(bg, cx - BTN_SZ / 2, BTN_CY - BTN_SZ / 2,
|
||||||
|
RGBA8(46, 46, 52, 255));
|
||||||
|
int isz = 26;
|
||||||
|
vita2d_texture *g = icon_tex(icon, isz);
|
||||||
|
if (g)
|
||||||
|
vita2d_draw_texture_tint(g, cx - isz / 2.0f, BTN_CY - isz / 2.0f,
|
||||||
|
RGBA8(190, 190, 196, 255));
|
||||||
|
}
|
||||||
|
|
||||||
static void draw_search_bar(void)
|
static void draw_search_bar(void)
|
||||||
{
|
{
|
||||||
unsigned int field = RGBA8(38, 38, 42, 255);
|
unsigned int field = RGBA8(38, 38, 42, 255);
|
||||||
@@ -1994,12 +2163,16 @@ static void draw_search_bar(void)
|
|||||||
vita2d_draw_rectangle(BAR_M, BAR_Y, BAR_W, BAR_H, field);
|
vita2d_draw_rectangle(BAR_M, BAR_Y, BAR_W, BAR_H, field);
|
||||||
|
|
||||||
int isz = 24;
|
int isz = 24;
|
||||||
vita2d_texture *icon = search_icon_tex(isz);
|
vita2d_texture *icon = icon_tex(ICON_SEARCH, isz);
|
||||||
if (icon)
|
if (icon)
|
||||||
vita2d_draw_texture_tint(icon, BAR_M + 22 - isz / 2.0f,
|
vita2d_draw_texture_tint(icon, BAR_M + 22 - isz / 2.0f,
|
||||||
BAR_Y + BAR_H / 2 - isz / 2.0f,
|
BAR_Y + BAR_H / 2 - isz / 2.0f,
|
||||||
RGBA8(190, 190, 196, 255));
|
RGBA8(190, 190, 196, 255));
|
||||||
|
|
||||||
|
/* placeholder buttons (map, cloud) for future features */
|
||||||
|
draw_bar_button(BTN1_CX, ICON_MAP);
|
||||||
|
draw_bar_button(BTN2_CX, ICON_CLOUD);
|
||||||
|
|
||||||
float tx = BAR_M + 44, ty = BAR_Y + BAR_H - 13;
|
float tx = BAR_M + 44, ty = BAR_Y + BAR_H - 13;
|
||||||
if (g_search_active && g_search_query[0]) {
|
if (g_search_active && g_search_query[0]) {
|
||||||
char q[64];
|
char q[64];
|
||||||
@@ -3510,39 +3683,11 @@ static int count_state(int st)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *state_name(int st)
|
|
||||||
{
|
|
||||||
switch (st) {
|
|
||||||
case SYNC_UNSCANNED: return "not scanned";
|
|
||||||
case SYNC_HASHING: return "hashing";
|
|
||||||
case SYNC_CHECKING: return "checking server";
|
|
||||||
case SYNC_LOCAL_ONLY:return "local only";
|
|
||||||
case SYNC_QUEUED: return "queued";
|
|
||||||
case SYNC_UPLOADING: return "uploading";
|
|
||||||
case SYNC_BACKED_UP: return "backed up";
|
|
||||||
case SYNC_FAILED: return "failed";
|
|
||||||
default: return "?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* format a byte count as B / KB / MB / GB into `out` */
|
|
||||||
static void human_size(long long bytes, char *out, size_t len)
|
|
||||||
{
|
|
||||||
if (bytes >= 1024LL * 1024 * 1024)
|
|
||||||
snprintf(out, len, "%.1f GB", bytes / (1024.0 * 1024 * 1024));
|
|
||||||
else if (bytes >= 1024LL * 1024)
|
|
||||||
snprintf(out, len, "%.1f MB", bytes / (1024.0 * 1024));
|
|
||||||
else if (bytes >= 1024)
|
|
||||||
snprintf(out, len, "%.1f KB", bytes / 1024.0);
|
|
||||||
else
|
|
||||||
snprintf(out, len, "%lld B", bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
/* main */
|
/* main */
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
enum { MODE_GRID, MODE_DETAIL, MODE_SYNC };
|
enum { MODE_GRID, MODE_DETAIL, MODE_CLOUD, MODE_CLOUD_DETAILS };
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
@@ -3651,8 +3796,8 @@ int main(void)
|
|||||||
sceKernelStartThread(syncw, 0, NULL);
|
sceKernelStartThread(syncw, 0, NULL);
|
||||||
|
|
||||||
int mode = MODE_GRID;
|
int mode = MODE_GRID;
|
||||||
int sync_return_mode = MODE_GRID;
|
|
||||||
int sel = 0;
|
int sel = 0;
|
||||||
|
int cloud_scroll = 0; /* first visible row on the upload-details list */
|
||||||
/* periodic check for photos added to the server while we run */
|
/* periodic check for photos added to the server while we run */
|
||||||
uint64_t last_poll = sceKernelGetProcessTimeWide();
|
uint64_t last_poll = sceKernelGetProcessTimeWide();
|
||||||
int grid_last_sel = -1; /* sel at the previous frame */
|
int grid_last_sel = -1; /* sel at the previous frame */
|
||||||
@@ -3722,13 +3867,6 @@ int main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SELECT toggles the sync overview from the grid / detail view */
|
|
||||||
if ((pressed & SCE_CTRL_SELECT) && mode != MODE_SYNC) {
|
|
||||||
sync_return_mode = mode;
|
|
||||||
mode = MODE_SYNC;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* d-pad auto-repeat for fast scrolling */
|
/* d-pad auto-repeat for fast scrolling */
|
||||||
const unsigned int dirs = SCE_CTRL_UP | SCE_CTRL_DOWN |
|
const unsigned int dirs = SCE_CTRL_UP | SCE_CTRL_DOWN |
|
||||||
SCE_CTRL_LEFT | SCE_CTRL_RIGHT;
|
SCE_CTRL_LEFT | SCE_CTRL_RIGHT;
|
||||||
@@ -3744,6 +3882,7 @@ int main(void)
|
|||||||
int do_search_open = (pressed & SCE_CTRL_TRIANGLE) != 0;
|
int do_search_open = (pressed & SCE_CTRL_TRIANGLE) != 0;
|
||||||
int do_search_clear = g_search_active &&
|
int do_search_clear = g_search_active &&
|
||||||
(pressed & SCE_CTRL_CIRCLE) != 0;
|
(pressed & SCE_CTRL_CIRCLE) != 0;
|
||||||
|
int do_open_cloud = 0; /* tap on the cloud button */
|
||||||
|
|
||||||
if (nav & SCE_CTRL_RIGHT)
|
if (nav & SCE_CTRL_RIGHT)
|
||||||
sel++;
|
sel++;
|
||||||
@@ -3887,10 +4026,18 @@ int main(void)
|
|||||||
} else if (touch_active) {
|
} else if (touch_active) {
|
||||||
touch_active = 0;
|
touch_active = 0;
|
||||||
if (touch_on_bar) {
|
if (touch_on_bar) {
|
||||||
/* tap on the search bar: clear
|
/* tap on the bar: the map/cloud
|
||||||
* chip while a search is on, else
|
* buttons are placeholders (no-op),
|
||||||
* open the keyboard */
|
* the clear chip clears an active
|
||||||
if (g_search_active &&
|
* search, the field opens the
|
||||||
|
* keyboard */
|
||||||
|
if (touch_x > BTN2_CX - BTN_SZ / 2) {
|
||||||
|
/* cloud button: open the
|
||||||
|
* server/backup page */
|
||||||
|
do_open_cloud = 1;
|
||||||
|
} else if (touch_x > BAR_M + BAR_W) {
|
||||||
|
/* map button (placeholder) */
|
||||||
|
} else if (g_search_active &&
|
||||||
touch_x > BAR_CLEAR_CX - 16)
|
touch_x > BAR_CLEAR_CX - 16)
|
||||||
do_search_clear = 1;
|
do_search_clear = 1;
|
||||||
else
|
else
|
||||||
@@ -3928,6 +4075,11 @@ int main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (do_open_cloud) {
|
||||||
|
mode = MODE_CLOUD;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* act on a search request from TRIANGLE/CIRCLE
|
/* act on a search request from TRIANGLE/CIRCLE
|
||||||
* or a tap on the bar. both block this frame
|
* or a tap on the bar. both block this frame
|
||||||
* (keyboard / request), so restart the loop. */
|
* (keyboard / request), so restart the loop. */
|
||||||
@@ -4141,7 +4293,7 @@ int main(void)
|
|||||||
else
|
else
|
||||||
snprintf(hud, sizeof(hud),
|
snprintf(hud, sizeof(hud),
|
||||||
"%d / %d%s %.10s X view /\\ search "
|
"%d / %d%s %.10s X view /\\ search "
|
||||||
"SELECT sync START exit",
|
"START exit",
|
||||||
sel + 1, g_disp_count,
|
sel + 1, g_disp_count,
|
||||||
g_next_page > 0 ? "+" : "",
|
g_next_page > 0 ? "+" : "",
|
||||||
g_disp_count > 0 ? disp_date(sel) : "");
|
g_disp_count > 0 ? disp_date(sel) : "");
|
||||||
@@ -4589,142 +4741,214 @@ pf_skip:
|
|||||||
|
|
||||||
vita2d_end_drawing();
|
vita2d_end_drawing();
|
||||||
vita2d_swap_buffers();
|
vita2d_swap_buffers();
|
||||||
} else { /* MODE_SYNC */
|
} else if (mode == MODE_CLOUD) {
|
||||||
if ((pressed & SCE_CTRL_CIRCLE) ||
|
/* server + backup overview, opened from the cloud
|
||||||
(pressed & SCE_CTRL_SELECT)) {
|
* button on the search bar */
|
||||||
mode = sync_return_mode;
|
if (g_srv_state == 0) {
|
||||||
detail_idx = -1; /* re-decode on return to detail */
|
show_status("Loading server info...");
|
||||||
|
fetch_server_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
int total = g_local_count;
|
||||||
|
int backed = count_state(SYNC_BACKED_UP);
|
||||||
|
int remain = total - backed;
|
||||||
|
|
||||||
|
/* on-screen action buttons (also X = details, /\ = upload) */
|
||||||
|
float bth = 46, bty = 404;
|
||||||
|
float dbx = 60, dbw = 360; /* See details */
|
||||||
|
float ubx = dbx + dbw + 20, ubw = 320; /* Upload all */
|
||||||
|
int go_details = (pressed & SCE_CTRL_CROSS) != 0;
|
||||||
|
int do_upload = (pressed & SCE_CTRL_TRIANGLE) != 0;
|
||||||
|
|
||||||
|
if (pressed & SCE_CTRL_CIRCLE) {
|
||||||
|
mode = MODE_GRID;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pressed & SCE_CTRL_CROSS) {
|
|
||||||
|
/* touch: tap the button to open the details list */
|
||||||
|
{
|
||||||
|
SceTouchData td;
|
||||||
|
sceTouchPeek(SCE_TOUCH_PORT_FRONT, &td, 1);
|
||||||
|
if (td.reportNum > 0) {
|
||||||
|
float tx = td.report[0].x * 0.5f;
|
||||||
|
float ty = td.report[0].y * 0.5f;
|
||||||
|
if (!touch_active) {
|
||||||
|
touch_active = 1;
|
||||||
|
touch_dragged = 0;
|
||||||
|
touch_start_x = tx;
|
||||||
|
touch_start_y = ty;
|
||||||
|
} else if (fabsf(tx - touch_start_x) > 12 ||
|
||||||
|
fabsf(ty - touch_start_y) > 12) {
|
||||||
|
touch_dragged = 1;
|
||||||
|
}
|
||||||
|
touch_x = tx;
|
||||||
|
touch_y = ty;
|
||||||
|
} else if (touch_active) {
|
||||||
|
touch_active = 0;
|
||||||
|
if (!touch_dragged && touch_y >= bty &&
|
||||||
|
touch_y <= bty + bth) {
|
||||||
|
if (touch_x >= dbx &&
|
||||||
|
touch_x <= dbx + dbw)
|
||||||
|
go_details = 1;
|
||||||
|
else if (touch_x >= ubx &&
|
||||||
|
touch_x <= ubx + ubw)
|
||||||
|
do_upload = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_upload) {
|
||||||
int q = queue_all_uploads();
|
int q = queue_all_uploads();
|
||||||
log_line("sync: queued %d uploads", q);
|
log_line("cloud: queued %d uploads", q);
|
||||||
}
|
}
|
||||||
|
if (go_details) {
|
||||||
int backed = count_state(SYNC_BACKED_UP);
|
mode = MODE_CLOUD_DETAILS;
|
||||||
int local_only = count_state(SYNC_LOCAL_ONLY);
|
cloud_scroll = 0;
|
||||||
int queued = count_state(SYNC_QUEUED) +
|
continue;
|
||||||
count_state(SYNC_UPLOADING);
|
|
||||||
int failed = count_state(SYNC_FAILED);
|
|
||||||
int pending = count_state(SYNC_UNSCANNED) +
|
|
||||||
count_state(SYNC_HASHING) +
|
|
||||||
count_state(SYNC_CHECKING);
|
|
||||||
|
|
||||||
/* photo/video split + total and backed-up byte totals */
|
|
||||||
int srv_vid = 0;
|
|
||||||
for (int i = 0; i < g_asset_count; i++)
|
|
||||||
srv_vid += g_asset_is_video[i] ? 1 : 0;
|
|
||||||
int loc_vid = 0;
|
|
||||||
long long loc_bytes = 0, backed_bytes = 0;
|
|
||||||
for (int j = 0; j < g_local_count; j++) {
|
|
||||||
loc_vid += g_local_is_video[j] ? 1 : 0;
|
|
||||||
loc_bytes += g_local_size[j];
|
|
||||||
if (g_local_state[j] == SYNC_BACKED_UP)
|
|
||||||
backed_bytes += g_local_size[j];
|
|
||||||
}
|
}
|
||||||
int loc_pct = g_local_count ? (backed * 100 / g_local_count) : 0;
|
|
||||||
|
|
||||||
vita2d_start_drawing();
|
vita2d_start_drawing();
|
||||||
vita2d_clear_screen();
|
vita2d_clear_screen();
|
||||||
|
draw_centered(40, RGBA8(255, 255, 255, 255),
|
||||||
|
"Server & Backup");
|
||||||
|
|
||||||
draw_centered(40, RGBA8(255, 255, 255, 255), "Sync overview");
|
char line[300];
|
||||||
|
|
||||||
char line[200], sz1[24], sz2[24];
|
|
||||||
int y = 84;
|
|
||||||
uint32_t c = RGBA8(220, 220, 220, 255);
|
uint32_t c = RGBA8(220, 220, 220, 255);
|
||||||
snprintf(line, sizeof(line),
|
uint32_t dim = RGBA8(150, 150, 155, 255);
|
||||||
"Server assets: %d%s (%d photos, %d videos)",
|
int y = 92;
|
||||||
g_asset_count, g_next_page > 0 ? "+" : "",
|
|
||||||
g_asset_count - srv_vid, srv_vid);
|
|
||||||
draw_text(60, y, c, 1.0f, line); y += 30;
|
|
||||||
human_size(loc_bytes, sz1, sizeof(sz1));
|
|
||||||
snprintf(line, sizeof(line),
|
|
||||||
"Local files: %d (%d photos, %d videos) %s",
|
|
||||||
g_local_count, g_local_count - loc_vid, loc_vid, sz1);
|
|
||||||
draw_text(60, y, c, 1.0f, line); y += 30;
|
|
||||||
snprintf(line, sizeof(line),
|
|
||||||
"backed up %d local-only %d queued/uploading %d",
|
|
||||||
backed, local_only, queued);
|
|
||||||
draw_text(60, y, c, 1.0f, line); y += 30;
|
|
||||||
snprintf(line, sizeof(line), "scanning/hashing %d failed %d",
|
|
||||||
pending, failed);
|
|
||||||
draw_text(60, y, c, 1.0f, line); y += 30;
|
|
||||||
human_size(backed_bytes, sz1, sizeof(sz1));
|
|
||||||
human_size(loc_bytes, sz2, sizeof(sz2));
|
|
||||||
snprintf(line, sizeof(line),
|
|
||||||
"Backed up: %d%% of local (%s / %s)",
|
|
||||||
loc_pct, sz1, sz2);
|
|
||||||
draw_text(60, y,
|
|
||||||
RGBA8(120, 200, 120, 255), 1.0f, line);
|
|
||||||
y += 38;
|
|
||||||
|
|
||||||
/* details of the item currently selected in the grid */
|
/* server storage with a usage bar */
|
||||||
if (g_disp_count > 0 && sel >= 0 && sel < g_disp_count) {
|
if (g_srv_state == 1 && g_srv_total[0]) {
|
||||||
struct disp_item *si = &g_disp[sel];
|
snprintf(line, sizeof(line),
|
||||||
const char *name;
|
"Server storage: %s of %s used (%d%%)",
|
||||||
if (si->src == SRC_LOCAL) {
|
g_srv_use[0] ? g_srv_use : "?",
|
||||||
const char *p = g_local_path[si->idx];
|
g_srv_total, g_srv_pct);
|
||||||
|
draw_text(60, y, c, 1.0f, line);
|
||||||
|
y += 24;
|
||||||
|
float bw = 600, bh = 14;
|
||||||
|
vita2d_draw_rectangle(60, y, bw, bh,
|
||||||
|
RGBA8(48, 48, 54, 255));
|
||||||
|
float f = g_srv_pct / 100.0f;
|
||||||
|
if (f < 0) f = 0;
|
||||||
|
if (f > 1) f = 1;
|
||||||
|
vita2d_draw_rectangle(60, y, bw * f, bh,
|
||||||
|
RGBA8(94, 110, 215, 255));
|
||||||
|
y += 40;
|
||||||
|
} else {
|
||||||
|
draw_text(60, y, dim, 1.0f,
|
||||||
|
"Server storage: unavailable");
|
||||||
|
y += 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(line, sizeof(line), "Server version: %s",
|
||||||
|
g_srv_version[0] ? g_srv_version : "unknown");
|
||||||
|
draw_text(60, y, c, 1.0f, line); y += 30;
|
||||||
|
snprintf(line, sizeof(line), "Server URL: %.48s", g_server);
|
||||||
|
draw_text(60, y, c, 1.0f, line); y += 30;
|
||||||
|
snprintf(line, sizeof(line), "App version: %s", APP_VERSION);
|
||||||
|
draw_text(60, y, c, 1.0f, line); y += 44;
|
||||||
|
|
||||||
|
draw_text(60, y, RGBA8(255, 255, 255, 255), 1.0f,
|
||||||
|
"On this PS Vita"); y += 30;
|
||||||
|
snprintf(line, sizeof(line), " Images detected: %d", total);
|
||||||
|
draw_text(60, y, c, 1.0f, line); y += 28;
|
||||||
|
snprintf(line, sizeof(line), " Backed up: %d", backed);
|
||||||
|
draw_text(60, y, RGBA8(120, 200, 120, 255), 1.0f, line);
|
||||||
|
y += 28;
|
||||||
|
snprintf(line, sizeof(line), " Remaining: %d", remain);
|
||||||
|
draw_text(60, y, RGBA8(220, 180, 120, 255), 1.0f, line);
|
||||||
|
|
||||||
|
/* See details + Upload all buttons */
|
||||||
|
vita2d_texture *db = rounded_mask_tex((int)dbw, (int)bth, 10.0f);
|
||||||
|
if (db)
|
||||||
|
vita2d_draw_texture_tint(db, dbx, bty,
|
||||||
|
RGBA8(46, 46, 52, 255));
|
||||||
|
else
|
||||||
|
vita2d_draw_rectangle(dbx, bty, dbw, bth,
|
||||||
|
RGBA8(46, 46, 52, 255));
|
||||||
|
snprintf(line, sizeof(line), "See details (%d remaining)", remain);
|
||||||
|
draw_text(dbx + 18, bty + bth - 16,
|
||||||
|
RGBA8(230, 230, 235, 255), 0.95f, line);
|
||||||
|
|
||||||
|
vita2d_texture *ub = rounded_mask_tex((int)ubw, (int)bth, 10.0f);
|
||||||
|
/* the upload button reads as active (indigo) when there's
|
||||||
|
* something to send, dimmed when everything is backed up */
|
||||||
|
uint32_t uc = remain > 0 ? RGBA8(94, 110, 215, 255)
|
||||||
|
: RGBA8(46, 46, 52, 255);
|
||||||
|
if (ub)
|
||||||
|
vita2d_draw_texture_tint(ub, ubx, bty, uc);
|
||||||
|
else
|
||||||
|
vita2d_draw_rectangle(ubx, bty, ubw, bth, uc);
|
||||||
|
draw_text(ubx + 18, bty + bth - 16,
|
||||||
|
RGBA8(245, 245, 250, 255), 0.95f, "Upload all");
|
||||||
|
|
||||||
|
draw_hud("X / tap details /\\ / tap upload all O back START exit");
|
||||||
|
vita2d_end_drawing();
|
||||||
|
vita2d_swap_buffers();
|
||||||
|
} else if (mode == MODE_CLOUD_DETAILS) {
|
||||||
|
/* scrollable list of not-backed-up local files + status */
|
||||||
|
if (pressed & SCE_CTRL_CIRCLE) {
|
||||||
|
mode = MODE_CLOUD;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int top = 86, rowh = 28, rows = (SCREEN_H - top - 40) / rowh;
|
||||||
|
int total_unbacked = g_local_count - count_state(SYNC_BACKED_UP);
|
||||||
|
int maxscroll = total_unbacked - rows;
|
||||||
|
if (maxscroll < 0)
|
||||||
|
maxscroll = 0;
|
||||||
|
if (nav & SCE_CTRL_DOWN)
|
||||||
|
cloud_scroll++;
|
||||||
|
if (nav & SCE_CTRL_UP)
|
||||||
|
cloud_scroll--;
|
||||||
|
if (cloud_scroll > maxscroll)
|
||||||
|
cloud_scroll = maxscroll;
|
||||||
|
if (cloud_scroll < 0)
|
||||||
|
cloud_scroll = 0;
|
||||||
|
|
||||||
|
vita2d_start_drawing();
|
||||||
|
vita2d_clear_screen();
|
||||||
|
char line[300];
|
||||||
|
snprintf(line, sizeof(line), "Not backed up (%d)",
|
||||||
|
total_unbacked);
|
||||||
|
draw_centered(40, RGBA8(255, 255, 255, 255), line);
|
||||||
|
|
||||||
|
/* walk local files, skipping backed-up ones, render the
|
||||||
|
* window [cloud_scroll, cloud_scroll+rows) */
|
||||||
|
int seen = 0, drawn = 0, y = top;
|
||||||
|
for (int j = 0; j < g_local_count && drawn < rows; j++) {
|
||||||
|
if (g_local_state[j] == SYNC_BACKED_UP)
|
||||||
|
continue;
|
||||||
|
if (seen++ < cloud_scroll)
|
||||||
|
continue;
|
||||||
|
const char *p = g_local_path[j];
|
||||||
const char *slash = strrchr(p, '/');
|
const char *slash = strrchr(p, '/');
|
||||||
name = slash ? slash + 1 : p;
|
const char *name = slash ? slash + 1 : p;
|
||||||
} else {
|
int st = g_local_state[j];
|
||||||
name = g_asset_ids[si->idx];
|
const char *stx = st == SYNC_HASHING ? "hashing" :
|
||||||
|
st == SYNC_UPLOADING ? "uploading" :
|
||||||
|
st == SYNC_FAILED ? "failed" :
|
||||||
|
"waiting";
|
||||||
|
uint32_t sc = st == SYNC_UPLOADING ?
|
||||||
|
RGBA8(120, 200, 120, 255) :
|
||||||
|
st == SYNC_HASHING ?
|
||||||
|
RGBA8(220, 210, 120, 255) :
|
||||||
|
st == SYNC_FAILED ?
|
||||||
|
RGBA8(220, 120, 120, 255) :
|
||||||
|
RGBA8(170, 170, 178, 255);
|
||||||
|
snprintf(line, sizeof(line), "%.46s", name);
|
||||||
|
draw_text(40, y, RGBA8(220, 220, 220, 255),
|
||||||
|
0.9f, line);
|
||||||
|
draw_text(SCREEN_W - 170, y, sc, 0.9f, stx);
|
||||||
|
y += rowh;
|
||||||
|
drawn++;
|
||||||
}
|
}
|
||||||
snprintf(line, sizeof(line), "Selected: %.40s", name);
|
if (total_unbacked == 0)
|
||||||
draw_text(60, y, c, 0.95f, line);
|
draw_centered(SCREEN_H / 2,
|
||||||
y += 26;
|
|
||||||
if (si->src == SRC_LOCAL) {
|
|
||||||
human_size(g_local_size[si->idx], sz1,
|
|
||||||
sizeof(sz1));
|
|
||||||
snprintf(line, sizeof(line),
|
|
||||||
" %.19s %s %s%s",
|
|
||||||
g_local_date[si->idx], sz1,
|
|
||||||
g_local_is_video[si->idx] ?
|
|
||||||
"video, " : "photo, ",
|
|
||||||
state_name(g_local_state[si->idx]));
|
|
||||||
} else {
|
|
||||||
snprintf(line, sizeof(line),
|
|
||||||
" %.19s %s on server",
|
|
||||||
g_asset_dates[si->idx],
|
|
||||||
g_asset_is_video[si->idx] ?
|
|
||||||
"video" : "photo");
|
|
||||||
}
|
|
||||||
draw_text(60, y, c, 0.95f, line);
|
|
||||||
}
|
|
||||||
y += 36;
|
|
||||||
|
|
||||||
/* current activity + upload progress */
|
|
||||||
if (g_sync_activity[0]) {
|
|
||||||
if (g_sync_phase == 3 && g_ul_total > 0) {
|
|
||||||
float frac = (float)g_ul_now / (float)g_ul_total;
|
|
||||||
snprintf(line, sizeof(line), "%s %.0f%%",
|
|
||||||
g_sync_activity, frac * 100.0f);
|
|
||||||
} else {
|
|
||||||
snprintf(line, sizeof(line), "%s",
|
|
||||||
g_sync_activity);
|
|
||||||
}
|
|
||||||
draw_text(60, y,
|
|
||||||
RGBA8(120, 200, 120, 255),
|
RGBA8(120, 200, 120, 255),
|
||||||
1.0f, line);
|
"Everything is backed up");
|
||||||
}
|
|
||||||
y += 44;
|
|
||||||
|
|
||||||
if (g_sync_errn > 0) {
|
|
||||||
draw_text(60, y,
|
|
||||||
RGBA8(220, 120, 120, 255),
|
|
||||||
1.0f, "Recent errors:");
|
|
||||||
y += 30;
|
|
||||||
int shown = g_sync_errn < 5 ? g_sync_errn : 5;
|
|
||||||
for (int k = 0; k < shown && y < 480; k++) {
|
|
||||||
int e = (g_sync_errn - shown + k) % 5;
|
|
||||||
draw_text(60, y,
|
|
||||||
RGBA8(200, 160, 160, 255),
|
|
||||||
0.9f, g_sync_errlog[e]);
|
|
||||||
y += 26;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_hud("X upload all local-only O / SELECT back START exit");
|
|
||||||
|
|
||||||
|
draw_hud("Up/Down scroll O back START exit");
|
||||||
vita2d_end_drawing();
|
vita2d_end_drawing();
|
||||||
vita2d_swap_buffers();
|
vita2d_swap_buffers();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user