166 lines
4 KiB
C
166 lines
4 KiB
C
/**
|
|
* @file sync_screen_action.c
|
|
* @brief Backend-independent sync-screen keyboard action dispatcher.
|
|
*/
|
|
|
|
#include "trainlog/sync_screen_action.h"
|
|
|
|
#include "trainlog/terminal.h"
|
|
#include "trainlog/presentation.h"
|
|
|
|
static TrainlogSyncScreenAction sync_screen_action(
|
|
TrainlogSyncScreenEffect effect,
|
|
TrainlogSyncDirection direction
|
|
)
|
|
{
|
|
TrainlogSyncScreenAction action;
|
|
|
|
action.effect = effect;
|
|
action.direction = direction;
|
|
return action;
|
|
}
|
|
|
|
void trainlog_sync_screen_state_init(
|
|
TrainlogSyncScreenState *state
|
|
)
|
|
{
|
|
if (state == NULL) {
|
|
return;
|
|
}
|
|
|
|
state->confirming = false;
|
|
state->direction = TRAINLOG_SYNC_BIDIRECTIONAL;
|
|
}
|
|
|
|
TrainlogSyncScreenAction trainlog_sync_screen_dispatch(
|
|
TrainlogSyncScreenState *state,
|
|
int key
|
|
)
|
|
{
|
|
TrainlogSyncDirection direction;
|
|
|
|
if (state == NULL) {
|
|
return sync_screen_action(
|
|
TRAINLOG_SYNC_SCREEN_NONE,
|
|
TRAINLOG_SYNC_BIDIRECTIONAL
|
|
);
|
|
}
|
|
|
|
direction = state->direction;
|
|
|
|
/* CONTRACT: the desktop product exposes one sync operation. Directional
|
|
* engine modes remain an internal compatibility capability for receipts
|
|
* and existing callers, but the TUI always requests the complete exchange. */
|
|
if (key == 's' || key == 'S') {
|
|
direction = TRAINLOG_SYNC_BIDIRECTIONAL;
|
|
} else if (state->confirming) {
|
|
if (key == '\n' || key == TRAINLOG_KEY_ENTER) {
|
|
/* CONTRACT: consuming confirmation before execution guarantees
|
|
* that one Enter event can yield at most one sync-engine call. */
|
|
state->confirming = false;
|
|
return sync_screen_action(
|
|
TRAINLOG_SYNC_SCREEN_RUN,
|
|
state->direction
|
|
);
|
|
}
|
|
|
|
if (key == 27) {
|
|
state->confirming = false;
|
|
return sync_screen_action(
|
|
TRAINLOG_SYNC_SCREEN_CANCEL,
|
|
state->direction
|
|
);
|
|
}
|
|
|
|
return sync_screen_action(
|
|
TRAINLOG_SYNC_SCREEN_NONE,
|
|
state->direction
|
|
);
|
|
} else if (key == 'r' || key == 'R') {
|
|
return sync_screen_action(
|
|
TRAINLOG_SYNC_SCREEN_REFRESH,
|
|
state->direction
|
|
);
|
|
} else if (key == 27) {
|
|
return sync_screen_action(
|
|
TRAINLOG_SYNC_SCREEN_EXIT,
|
|
state->direction
|
|
);
|
|
} else {
|
|
return sync_screen_action(
|
|
TRAINLOG_SYNC_SCREEN_NONE,
|
|
state->direction
|
|
);
|
|
}
|
|
|
|
state->direction = direction;
|
|
state->confirming = true;
|
|
return sync_screen_action(
|
|
TRAINLOG_SYNC_SCREEN_CONFIRM,
|
|
direction
|
|
);
|
|
}
|
|
|
|
TrainlogStatus trainlog_sync_screen_execute(
|
|
const TrainlogSyncScreenAction *action,
|
|
TrainlogSyncScreenRunCallback callback,
|
|
void *context,
|
|
TrainlogSyncReport *report
|
|
)
|
|
{
|
|
if (
|
|
action == NULL ||
|
|
action->effect != TRAINLOG_SYNC_SCREEN_RUN ||
|
|
callback == NULL ||
|
|
report == NULL
|
|
) {
|
|
return TRAINLOG_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
|
|
return callback(
|
|
action->direction,
|
|
report,
|
|
context
|
|
);
|
|
}
|
|
|
|
const char *trainlog_sync_screen_direction_label(
|
|
TrainlogSyncDirection direction
|
|
)
|
|
{
|
|
if (direction == TRAINLOG_SYNC_ANDROID_TO_PC) {
|
|
return "Android→PC";
|
|
}
|
|
|
|
if (direction == TRAINLOG_SYNC_PC_TO_ANDROID) {
|
|
return "PC→Android";
|
|
}
|
|
|
|
return "PC↔Android";
|
|
}
|
|
|
|
const char *trainlog_sync_screen_confirmation(
|
|
TrainlogSyncDirection direction
|
|
)
|
|
{
|
|
if (direction == TRAINLOG_SYNC_ANDROID_TO_PC) {
|
|
return trainlog_presentation_text("sync.confirm.import");
|
|
}
|
|
|
|
if (direction == TRAINLOG_SYNC_PC_TO_ANDROID) {
|
|
return trainlog_presentation_text("sync.confirm.publish");
|
|
}
|
|
|
|
return trainlog_presentation_text("sync.confirm.both");
|
|
}
|
|
|
|
const char *trainlog_sync_screen_footer(
|
|
int terminal_columns
|
|
)
|
|
{
|
|
if (terminal_columns >= 100) {
|
|
return trainlog_presentation_text("sync.footer.wide");
|
|
}
|
|
|
|
return trainlog_presentation_text("sync.footer.compact");
|
|
}
|