Auto-fetch new photos, stable month jumps, video rotation, throbbers
- new photos on the server appear automatically: the grid polls the newest page every ~30 s while settled; dedup_new_assets drops already-known ids (and also guards page fetches against server-side pagination drift) - rebuild_keep_view pins the scroll and selection to the same photo across every relayout (page fetch, poll, sync), so loads no longer move the view - R/L month jump anchors the landed month's header to the top of the screen, and R fetches ahead until the next month is actually loaded - portrait videos play upright: the asset's exif orientation is kept (g_asset_rot) and the player rotates decoded frames (draw_video_frame) - "loading..." texts replaced by a spinning throbber: centered when an item has no preview yet, a small corner one while the full-res loads over the thumb (never both) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -53,3 +53,18 @@ Task list for the current round of work. Checked items are done.
|
|||||||
- [x] Verified: repeated 10–12 s held-scroll cycles to photo 1780+ across
|
- [x] Verified: repeated 10–12 s held-scroll cycles to photo 1780+ across
|
||||||
multiple pages, zero GPU faults / zero crashes (previous builds died
|
multiple pages, zero GPU faults / zero crashes (previous builds died
|
||||||
within ~10 s).
|
within ~10 s).
|
||||||
|
|
||||||
|
## 6. Open bugs / polish
|
||||||
|
- [x] R (month jump) lands on the next month, but when more pages load the
|
||||||
|
view shifts away from the landing spot — fixed: rebuild_keep_view pins
|
||||||
|
the scroll/selection to the same photo across every rebuild (page
|
||||||
|
fetch, poll, sync), and R now fetches ahead until the next month is
|
||||||
|
actually loaded before jumping.
|
||||||
|
- [x] R scrolls the jumped-to month to the top of the screen, header band
|
||||||
|
included.
|
||||||
|
- [x] Portrait videos play sideways — fixed: the asset's exif orientation
|
||||||
|
is kept (g_asset_rot) and the player rotates decoded frames upright
|
||||||
|
(draw_video_frame).
|
||||||
|
- [x] Replaced the "loading..." texts with a spinning throbber: centered
|
||||||
|
when there is no preview at all, a small corner one while the full-res
|
||||||
|
loads over the thumb.
|
||||||
|
|||||||
+214
-29
@@ -18,6 +18,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <math.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
@@ -91,6 +92,7 @@ static vita2d_pgf *g_font;
|
|||||||
static char (*g_asset_ids)[40];
|
static char (*g_asset_ids)[40];
|
||||||
static char (*g_asset_dates)[DATELEN]; /* YYYY-MM-DDTHH:MM:SS */
|
static char (*g_asset_dates)[DATELEN]; /* YYYY-MM-DDTHH:MM:SS */
|
||||||
static float *g_asset_ratio; /* display w/h from exif, 0 = unknown */
|
static float *g_asset_ratio; /* display w/h from exif, 0 = unknown */
|
||||||
|
static unsigned char *g_asset_rot; /* raw exif orientation (0 = none) */
|
||||||
static unsigned char *g_asset_is_video;
|
static unsigned char *g_asset_is_video;
|
||||||
/* set during display rebuild: a backed-up local file matches this server
|
/* set during display rebuild: a backed-up local file matches this server
|
||||||
* asset, so its grid cell shows the green "backed up" badge */
|
* asset, so its grid cell shows the green "backed up" badge */
|
||||||
@@ -219,6 +221,7 @@ static int grow_assets(int need)
|
|||||||
if (!GROW(g_asset_ids, c, need) ||
|
if (!GROW(g_asset_ids, c, need) ||
|
||||||
!GROW(g_asset_dates, c, need) ||
|
!GROW(g_asset_dates, c, need) ||
|
||||||
!GROW(g_asset_ratio, c, need) ||
|
!GROW(g_asset_ratio, c, need) ||
|
||||||
|
!GROW(g_asset_rot, c, need) ||
|
||||||
!GROW(g_asset_is_video, c, need) ||
|
!GROW(g_asset_is_video, c, need) ||
|
||||||
!GROW(g_asset_local_backed, c, need) ||
|
!GROW(g_asset_local_backed, c, need) ||
|
||||||
!GROW(g_thumb, c, need) ||
|
!GROW(g_thumb, c, need) ||
|
||||||
@@ -804,6 +807,8 @@ static int parse_assets(const char *js, size_t jslen, char *err, size_t errlen)
|
|||||||
if (cur >= 0 && exw > 0 && exh > 0)
|
if (cur >= 0 && exw > 0 && exh > 0)
|
||||||
g_asset_ratio[cur] = (exori >= 5 && exori <= 8) ?
|
g_asset_ratio[cur] = (exori >= 5 && exori <= 8) ?
|
||||||
(float)exh / exw : (float)exw / exh;
|
(float)exh / exw : (float)exw / exh;
|
||||||
|
if (cur >= 0)
|
||||||
|
g_asset_rot[cur] = (unsigned char)exori;
|
||||||
if (!grow_assets(g_asset_count + 1))
|
if (!grow_assets(g_asset_count + 1))
|
||||||
break; /* out of memory: keep what we have */
|
break; /* out of memory: keep what we have */
|
||||||
cur = g_asset_count++;
|
cur = g_asset_count++;
|
||||||
@@ -814,6 +819,7 @@ static int parse_assets(const char *js, size_t jslen, char *err, size_t errlen)
|
|||||||
g_asset_ids[cur][0] = '\0';
|
g_asset_ids[cur][0] = '\0';
|
||||||
g_asset_dates[cur][0] = '\0';
|
g_asset_dates[cur][0] = '\0';
|
||||||
g_asset_ratio[cur] = 0.0f;
|
g_asset_ratio[cur] = 0.0f;
|
||||||
|
g_asset_rot[cur] = 0;
|
||||||
g_asset_is_video[cur] = 0;
|
g_asset_is_video[cur] = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -865,6 +871,8 @@ static int parse_assets(const char *js, size_t jslen, char *err, size_t errlen)
|
|||||||
if (cur >= 0 && exw > 0 && exh > 0)
|
if (cur >= 0 && exw > 0 && exh > 0)
|
||||||
g_asset_ratio[cur] = (exori >= 5 && exori <= 8) ?
|
g_asset_ratio[cur] = (exori >= 5 && exori <= 8) ?
|
||||||
(float)exh / exw : (float)exw / exh;
|
(float)exh / exw : (float)exw / exh;
|
||||||
|
if (cur >= 0)
|
||||||
|
g_asset_rot[cur] = (unsigned char)exori;
|
||||||
free(tok);
|
free(tok);
|
||||||
|
|
||||||
/* drop trailing entries that somehow lack an id */
|
/* drop trailing entries that somehow lack an id */
|
||||||
@@ -876,6 +884,37 @@ static int parse_assets(const char *js, size_t jslen, char *err, size_t errlen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fetch the next page of the library, newest first; returns assets added */
|
/* fetch the next page of the library, newest first; returns assets added */
|
||||||
|
/* compact away just-parsed entries [before, g_asset_count) whose id already
|
||||||
|
* exists below `before` (the server's pages shift when assets are added or
|
||||||
|
* removed, so refetches can overlap). order among the new tail doesn't
|
||||||
|
* matter — the display rebuild sorts by date — and none of these have
|
||||||
|
* textures yet. returns how many genuinely new entries remain. */
|
||||||
|
static int dedup_new_assets(int before)
|
||||||
|
{
|
||||||
|
int n = g_asset_count;
|
||||||
|
for (int i = before; i < n; ) {
|
||||||
|
int dup = 0;
|
||||||
|
for (int j = 0; j < before && !dup; j++)
|
||||||
|
dup = !strcmp(g_asset_ids[j], g_asset_ids[i]);
|
||||||
|
if (!dup) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
n--;
|
||||||
|
if (i != n) {
|
||||||
|
memcpy(g_asset_ids[i], g_asset_ids[n],
|
||||||
|
sizeof(g_asset_ids[0]));
|
||||||
|
memcpy(g_asset_dates[i], g_asset_dates[n],
|
||||||
|
sizeof(g_asset_dates[0]));
|
||||||
|
g_asset_ratio[i] = g_asset_ratio[n];
|
||||||
|
g_asset_rot[i] = g_asset_rot[n];
|
||||||
|
g_asset_is_video[i] = g_asset_is_video[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_asset_count = n;
|
||||||
|
return n - before;
|
||||||
|
}
|
||||||
|
|
||||||
static int fetch_page(int is_first)
|
static int fetch_page(int is_first)
|
||||||
{
|
{
|
||||||
if (g_next_page <= 0)
|
if (g_next_page <= 0)
|
||||||
@@ -914,6 +953,7 @@ static int fetch_page(int is_first)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char err[160];
|
char err[160];
|
||||||
|
int before = g_asset_count;
|
||||||
int added = parse_assets(buf.data, buf.size, err, sizeof(err));
|
int added = parse_assets(buf.data, buf.size, err, sizeof(err));
|
||||||
if (added < 0) {
|
if (added < 0) {
|
||||||
if (is_first)
|
if (is_first)
|
||||||
@@ -925,14 +965,50 @@ static int fetch_page(int is_first)
|
|||||||
}
|
}
|
||||||
free(buf.data);
|
free(buf.data);
|
||||||
|
|
||||||
/* a short page means we reached the end of the library */
|
/* a short (raw) page means we reached the end of the library; the
|
||||||
|
* dedup below only filters overlap from server-side page drift */
|
||||||
g_next_page = (added == PAGE_SIZE) ? g_next_page + 1 : 0;
|
g_next_page = (added == PAGE_SIZE) ? g_next_page + 1 : 0;
|
||||||
|
int fresh = dedup_new_assets(before);
|
||||||
int with_ratio = 0;
|
int with_ratio = 0;
|
||||||
for (int i = g_asset_count - added; i < g_asset_count; i++)
|
for (int i = g_asset_count - fresh; i < g_asset_count; i++)
|
||||||
with_ratio += (g_asset_ratio[i] > 0.0f);
|
with_ratio += (g_asset_ratio[i] > 0.0f);
|
||||||
log_line("page fetched: +%d assets (total %d, %d with exif ratio)",
|
log_line("page fetched: +%d assets (total %d, %d with exif ratio)",
|
||||||
added, g_asset_count, with_ratio);
|
fresh, g_asset_count, with_ratio);
|
||||||
return added;
|
return fresh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* poll the newest page for photos added to the server since we fetched;
|
||||||
|
* duplicates of already-known assets are dropped, so only genuinely new
|
||||||
|
* items remain appended. main-thread only (mutates the asset arrays).
|
||||||
|
* returns the number of new assets. */
|
||||||
|
static int check_new_assets(void)
|
||||||
|
{
|
||||||
|
char url[600];
|
||||||
|
snprintf(url, sizeof(url), "%s/api/search/metadata", g_server);
|
||||||
|
char body[160];
|
||||||
|
snprintf(body, sizeof(body),
|
||||||
|
"{\"page\":1,\"size\":%d,\"order\":\"desc\",\"withExif\":true}",
|
||||||
|
PAGE_SIZE);
|
||||||
|
|
||||||
|
membuf buf;
|
||||||
|
long code;
|
||||||
|
CURLcode res = http_request(url, body, &buf, &code, NULL, 0);
|
||||||
|
if (res != CURLE_OK || code < 200 || code >= 300) {
|
||||||
|
free(buf.data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char err[160];
|
||||||
|
int before = g_asset_count;
|
||||||
|
int added = parse_assets(buf.data, buf.size, err, sizeof(err));
|
||||||
|
free(buf.data);
|
||||||
|
if (added <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int fresh = dedup_new_assets(before);
|
||||||
|
if (fresh > 0)
|
||||||
|
log_line("poll: %d new asset(s) on the server", fresh);
|
||||||
|
return fresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1454,6 +1530,33 @@ static void rebuild_display(void)
|
|||||||
layout_grid();
|
layout_grid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int find_disp(unsigned char src, int idx);
|
||||||
|
|
||||||
|
/* rebuild the display after the asset set changed, keeping the view glued
|
||||||
|
* to the photo the selection is on: the selection follows the item, and the
|
||||||
|
* scroll/target keep their offset relative to it, so a page fetch or poll
|
||||||
|
* relayout doesn't visibly move the grid. */
|
||||||
|
static void rebuild_keep_view(int *sel, float *scroll, float *target)
|
||||||
|
{
|
||||||
|
int had = (*sel >= 0 && *sel < g_disp_count);
|
||||||
|
struct disp_item keep = had ? g_disp[*sel] : (struct disp_item){ 0, 0 };
|
||||||
|
float dt = had ? *target - g_item_y[*sel] : 0.0f;
|
||||||
|
float ds = had ? *scroll - g_item_y[*sel] : 0.0f;
|
||||||
|
rebuild_display();
|
||||||
|
if (had) {
|
||||||
|
int ns = find_disp(keep.src, keep.idx);
|
||||||
|
if (ns >= 0) {
|
||||||
|
*sel = ns;
|
||||||
|
*target = g_item_y[ns] + dt;
|
||||||
|
*scroll = g_item_y[ns] + ds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*sel >= g_disp_count)
|
||||||
|
*sel = g_disp_count - 1;
|
||||||
|
if (*sel < 0)
|
||||||
|
*sel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* first item of the month-run after (dir>0, older) or before (dir<0, newer)
|
/* first item of the month-run after (dir>0, older) or before (dir<0, newer)
|
||||||
* the one containing display slot d; the timeline is "YYYY-MM"-grouped and
|
* the one containing display slot d; the timeline is "YYYY-MM"-grouped and
|
||||||
* date-descending, so a month is a contiguous run of equal 7-char prefixes */
|
* date-descending, so a month is a contiguous run of equal 7-char prefixes */
|
||||||
@@ -1656,6 +1759,21 @@ static void draw_hud(const char *text)
|
|||||||
RGBA8(255, 255, 255, 255), 1.0f, text);
|
RGBA8(255, 255, 255, 255), 1.0f, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* spinning throbber: a ring of dots with a brightness tail */
|
||||||
|
static void draw_throbber(float cx, float cy, float r, unsigned int frame)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 12; i++) {
|
||||||
|
float a = (float)i * (6.2831853f / 12.0f);
|
||||||
|
int phase = ((int)(frame / 3) - i) % 12;
|
||||||
|
if (phase < 0)
|
||||||
|
phase += 12;
|
||||||
|
unsigned char al = (unsigned char)(255 - phase * 18);
|
||||||
|
vita2d_draw_fill_circle(cx + cosf(a) * r, cy + sinf(a) * r,
|
||||||
|
r / 5.5f,
|
||||||
|
RGBA8(255, 255, 255, al));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* translucent play button over a video's poster in the detail view */
|
/* translucent play button over a video's poster in the detail view */
|
||||||
static void draw_play_overlay(void)
|
static void draw_play_overlay(void)
|
||||||
{
|
{
|
||||||
@@ -1728,6 +1846,39 @@ static uint64_t g_dl_last_draw;
|
|||||||
* play call sites, valid for the whole modal download + playback */
|
* play call sites, valid for the whole modal download + playback */
|
||||||
static vita2d_texture *g_dl_bg;
|
static vita2d_texture *g_dl_bg;
|
||||||
|
|
||||||
|
/* display rotation (degrees clockwise) of the video being played; from the
|
||||||
|
* asset's exif orientation, so portrait recordings play upright */
|
||||||
|
static int g_video_rot;
|
||||||
|
|
||||||
|
static int ori_to_deg(int o)
|
||||||
|
{
|
||||||
|
switch (o) {
|
||||||
|
case 3: case 4: return 180;
|
||||||
|
case 5: case 6: return 90;
|
||||||
|
case 7: case 8: return 270;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fit a (possibly rotated) video frame to the screen */
|
||||||
|
static void draw_video_frame(vita2d_texture *tex)
|
||||||
|
{
|
||||||
|
float w = vita2d_texture_get_width(tex);
|
||||||
|
float h = vita2d_texture_get_height(tex);
|
||||||
|
if (g_video_rot == 0) {
|
||||||
|
draw_texture_fitted(tex, 0, 0, SCREEN_W, SCREEN_H);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int side = (g_video_rot == 90 || g_video_rot == 270);
|
||||||
|
float ew = side ? h : w, eh = side ? w : h;
|
||||||
|
float sc = ((float)SCREEN_W / ew < (float)SCREEN_H / eh) ?
|
||||||
|
(float)SCREEN_W / ew : (float)SCREEN_H / eh;
|
||||||
|
vita2d_draw_texture_scale_rotate(tex, SCREEN_W / 2.0f, SCREEN_H / 2.0f,
|
||||||
|
sc, sc,
|
||||||
|
(float)g_video_rot *
|
||||||
|
(3.14159265f / 180.0f));
|
||||||
|
}
|
||||||
|
|
||||||
/* full-screen status with the video's poster behind it */
|
/* full-screen status with the video's poster behind it */
|
||||||
static void show_video_status(const char *text)
|
static void show_video_status(const char *text)
|
||||||
{
|
{
|
||||||
@@ -2233,7 +2384,7 @@ replay:
|
|||||||
vita2d_start_drawing();
|
vita2d_start_drawing();
|
||||||
vita2d_clear_screen();
|
vita2d_clear_screen();
|
||||||
if (cur)
|
if (cur)
|
||||||
draw_texture_fitted(cur, 0, 0, SCREEN_W, SCREEN_H);
|
draw_video_frame(cur);
|
||||||
else if (g_dl_bg)
|
else if (g_dl_bg)
|
||||||
/* poster until the first decoded frame arrives */
|
/* poster until the first decoded frame arrives */
|
||||||
draw_texture_fitted(g_dl_bg, 0, 0, SCREEN_W, SCREEN_H);
|
draw_texture_fitted(g_dl_bg, 0, 0, SCREEN_W, SCREEN_H);
|
||||||
@@ -2289,7 +2440,7 @@ replay:
|
|||||||
vita2d_start_drawing();
|
vita2d_start_drawing();
|
||||||
vita2d_clear_screen();
|
vita2d_clear_screen();
|
||||||
if (cur)
|
if (cur)
|
||||||
draw_texture_fitted(cur, 0, 0, SCREEN_W, SCREEN_H);
|
draw_video_frame(cur);
|
||||||
draw_hud("ended X replay O back");
|
draw_hud("ended X replay O back");
|
||||||
vita2d_end_drawing();
|
vita2d_end_drawing();
|
||||||
vita2d_swap_buffers();
|
vita2d_swap_buffers();
|
||||||
@@ -2322,6 +2473,7 @@ static void view_video(int idx)
|
|||||||
* asset thumb. the modal download keeps the texture alive. */
|
* asset thumb. the modal download keeps the texture alive. */
|
||||||
if (!g_dl_bg)
|
if (!g_dl_bg)
|
||||||
g_dl_bg = g_thumb[idx];
|
g_dl_bg = g_thumb[idx];
|
||||||
|
g_video_rot = ori_to_deg(g_asset_rot[idx]);
|
||||||
|
|
||||||
char err[160];
|
char err[160];
|
||||||
int r = download_video(idx, err, sizeof(err));
|
int r = download_video(idx, err, sizeof(err));
|
||||||
@@ -3038,6 +3190,8 @@ int main(void)
|
|||||||
int mode = MODE_GRID;
|
int mode = MODE_GRID;
|
||||||
int sync_return_mode = MODE_GRID;
|
int sync_return_mode = MODE_GRID;
|
||||||
int sel = 0;
|
int sel = 0;
|
||||||
|
/* periodic check for photos added to the server while we run */
|
||||||
|
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 */
|
||||||
int grid_settle = 0; /* frames since sel last changed */
|
int grid_settle = 0; /* frames since sel last changed */
|
||||||
float scroll = 0.0f, target = 0.0f;
|
float scroll = 0.0f, target = 0.0f;
|
||||||
@@ -3090,17 +3244,7 @@ int main(void)
|
|||||||
* on the same photo across the reorder */
|
* on the same photo across the reorder */
|
||||||
if (g_need_rebuild) {
|
if (g_need_rebuild) {
|
||||||
g_need_rebuild = 0;
|
g_need_rebuild = 0;
|
||||||
int had = (sel >= 0 && sel < g_disp_count);
|
rebuild_keep_view(&sel, &scroll, &target);
|
||||||
struct disp_item keep = had ? g_disp[sel]
|
|
||||||
: (struct disp_item){ 0, 0 };
|
|
||||||
rebuild_display();
|
|
||||||
if (had) {
|
|
||||||
int ns = find_disp(keep.src, keep.idx);
|
|
||||||
if (ns >= 0)
|
|
||||||
sel = ns;
|
|
||||||
}
|
|
||||||
if (sel >= g_disp_count)
|
|
||||||
sel = g_disp_count - 1;
|
|
||||||
detail_idx = -1; /* re-decode: item under sel may differ */
|
detail_idx = -1; /* re-decode: item under sel may differ */
|
||||||
/* display slots were reshuffled: the prefetch cache's
|
/* display slots were reshuffled: the prefetch cache's
|
||||||
* slot keys are meaningless now */
|
* slot keys are meaningless now */
|
||||||
@@ -3142,10 +3286,31 @@ int main(void)
|
|||||||
sel = nav_row(sel, +1);
|
sel = nav_row(sel, +1);
|
||||||
if (nav & SCE_CTRL_UP)
|
if (nav & SCE_CTRL_UP)
|
||||||
sel = nav_row(sel, -1);
|
sel = nav_row(sel, -1);
|
||||||
if (pressed & SCE_CTRL_RTRIGGER)
|
if ((pressed & (SCE_CTRL_RTRIGGER |
|
||||||
sel = month_jump(sel, +1); /* older month */
|
SCE_CTRL_LTRIGGER)) &&
|
||||||
if (pressed & SCE_CTRL_LTRIGGER)
|
g_disp_count > 0) {
|
||||||
sel = month_jump(sel, -1); /* newer month */
|
int dir = (pressed & SCE_CTRL_RTRIGGER) ?
|
||||||
|
+1 : -1;
|
||||||
|
/* jumping down: the next month may simply not
|
||||||
|
* be fetched yet — pull pages until a new
|
||||||
|
* month shows up (or the library ends) */
|
||||||
|
if (dir > 0) {
|
||||||
|
int guard = 0;
|
||||||
|
while (g_next_page > 0 && guard++ < 10 &&
|
||||||
|
!strncmp(disp_date(month_jump(sel, +1)),
|
||||||
|
disp_date(sel), 7)) {
|
||||||
|
if (fetch_page(0) <= 0)
|
||||||
|
break;
|
||||||
|
rebuild_keep_view(&sel, &scroll,
|
||||||
|
&target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sel = month_jump(sel, dir);
|
||||||
|
/* put the jumped-to month at the top of the
|
||||||
|
* screen, header band included */
|
||||||
|
if (sel >= 0 && sel < g_disp_count)
|
||||||
|
target = g_item_y[sel] - HEADER_H;
|
||||||
|
}
|
||||||
|
|
||||||
/* Track how long the selection has held still. A held
|
/* Track how long the selection has held still. A held
|
||||||
* d-pad auto-repeats one row every few frames; while it's
|
* d-pad auto-repeats one row every few frames; while it's
|
||||||
@@ -3184,9 +3349,21 @@ int main(void)
|
|||||||
if (!scrolling_fast && g_next_page > 0 &&
|
if (!scrolling_fast && g_next_page > 0 &&
|
||||||
sel >= g_disp_count - COLS * 4) {
|
sel >= g_disp_count - COLS * 4) {
|
||||||
if (fetch_page(0) > 0)
|
if (fetch_page(0) > 0)
|
||||||
rebuild_display();
|
rebuild_keep_view(&sel, &scroll,
|
||||||
if (sel >= g_disp_count)
|
&target);
|
||||||
sel = g_disp_count - 1;
|
}
|
||||||
|
|
||||||
|
/* photos added to the server show up by themselves:
|
||||||
|
* poll the newest page every ~30 s while the grid is
|
||||||
|
* settled, keeping the selection on the same photo
|
||||||
|
* across the relayout */
|
||||||
|
uint64_t pnow = sceKernelGetProcessTimeWide();
|
||||||
|
if (!scrolling_fast && !touch_active &&
|
||||||
|
pnow - last_poll > 30ULL * 1000 * 1000) {
|
||||||
|
last_poll = pnow;
|
||||||
|
if (check_new_assets() > 0)
|
||||||
|
rebuild_keep_view(&sel, &scroll,
|
||||||
|
&target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* front touch: drag scrolls the timeline directly, a
|
/* front touch: drag scrolls the timeline directly, a
|
||||||
@@ -3512,6 +3689,7 @@ int main(void)
|
|||||||
g_dl_bg = detail_tex ?
|
g_dl_bg = detail_tex ?
|
||||||
detail_tex :
|
detail_tex :
|
||||||
disp_thumb(sel);
|
disp_thumb(sel);
|
||||||
|
g_video_rot = 0;
|
||||||
if (is_local)
|
if (is_local)
|
||||||
play_video_file(g_local_path[it.idx]);
|
play_video_file(g_local_path[it.idx]);
|
||||||
else
|
else
|
||||||
@@ -3565,6 +3743,7 @@ int main(void)
|
|||||||
/* play even if the poster fetch failed */
|
/* play even if the poster fetch failed */
|
||||||
g_dl_bg = detail_tex ?
|
g_dl_bg = detail_tex ?
|
||||||
detail_tex : disp_thumb(sel);
|
detail_tex : disp_thumb(sel);
|
||||||
|
g_video_rot = 0;
|
||||||
if (is_local)
|
if (is_local)
|
||||||
play_video_file(g_local_path[it.idx]);
|
play_video_file(g_local_path[it.idx]);
|
||||||
else
|
else
|
||||||
@@ -3812,9 +3991,9 @@ pf_skip:
|
|||||||
draw_texture_fitted(th, 0, 0,
|
draw_texture_fitted(th, 0, 0,
|
||||||
SCREEN_W, SCREEN_H);
|
SCREEN_W, SCREEN_H);
|
||||||
else
|
else
|
||||||
draw_centered(SCREEN_H / 2,
|
draw_throbber(SCREEN_W / 2.0f,
|
||||||
RGBA8(160, 160, 160, 255),
|
SCREEN_H / 2.0f,
|
||||||
"Loading...");
|
28.0f, frame);
|
||||||
} else if (it.src == SRC_SERVER) {
|
} else if (it.src == SRC_SERVER) {
|
||||||
draw_error_detail(it.idx);
|
draw_error_detail(it.idx);
|
||||||
} else {
|
} else {
|
||||||
@@ -3832,12 +4011,18 @@ pf_skip:
|
|||||||
sel + 1, g_disp_count, zoom * 100.0f);
|
sel + 1, g_disp_count, zoom * 100.0f);
|
||||||
else
|
else
|
||||||
snprintf(hud, sizeof(hud),
|
snprintf(hud, sizeof(hud),
|
||||||
"%d / %d %.19s %s< > browse L/R zoom %sO back",
|
"%d / %d %.19s < > browse L/R zoom %sO back",
|
||||||
sel + 1, g_disp_count,
|
sel + 1, g_disp_count,
|
||||||
g_disp_count > 0 ? disp_date(sel) : "",
|
g_disp_count > 0 ? disp_date(sel) : "",
|
||||||
detail_loading ? "loading... " : "",
|
|
||||||
xhint);
|
xhint);
|
||||||
draw_hud(hud);
|
draw_hud(hud);
|
||||||
|
/* ...and a discreet corner throbber while the
|
||||||
|
* full-res image is still on its way — but only when
|
||||||
|
* a preview is showing; with no preview at all the
|
||||||
|
* big centered throbber is already up */
|
||||||
|
if (detail_loading && disp_thumb(sel))
|
||||||
|
draw_throbber(SCREEN_W - 36.0f, 36.0f,
|
||||||
|
14.0f, frame);
|
||||||
|
|
||||||
vita2d_end_drawing();
|
vita2d_end_drawing();
|
||||||
vita2d_swap_buffers();
|
vita2d_swap_buffers();
|
||||||
|
|||||||
Reference in New Issue
Block a user