Login
1 branch 0 tags
Ben (Desktop/Arch) AGENTS.md b60dcff 29 days ago 82 Commits
moon / src / screens / wifi_screen.c
#include "wifi_screen.h"
#include <stdio.h>
#include <stdlib.h>
#include "../config.h"
#include "../network.h"
#include "../topbar.h"

static wifi_screen_state_t* screen_state;

static void back_event_cb(lv_event_t* e) {
	if (lv_event_get_code(e) == LV_EVENT_CLICKED) {
		navigate_back(SCREEN_SETTINGS);
	}
}

static void test_http_cb(lv_event_t* e) {
	if (lv_event_get_code(e) != LV_EVENT_CLICKED) {
		return;
	}
	screen_state->test_url = "http://example.com";
	if (network_is_connected()) {
		screen_state->test_phase = WIFI_TEST_RUNNING;
	} else {
		screen_state->test_phase = WIFI_TEST_CONNECTING;
	}
	lv_label_set_text(screen_state->result_label, "Testing HTTP...");
}

static void test_https_cb(lv_event_t* e) {
	if (lv_event_get_code(e) != LV_EVENT_CLICKED) {
		return;
	}
	screen_state->test_url = "https://detectportal.firefox.com/canonical.html";
	if (network_is_connected()) {
		screen_state->test_phase = WIFI_TEST_RUNNING;
	} else {
		screen_state->test_phase = WIFI_TEST_CONNECTING;
	}
	lv_label_set_text(screen_state->result_label, "Testing HTTPS...");
}

static void scan_cb(lv_event_t* e) {
	if (lv_event_get_code(e) != LV_EVENT_CLICKED) {
		return;
	}
	screen_state->test_phase = WIFI_TEST_SCANNING;
	lv_label_set_text(screen_state->result_label, "Scanning...");
}

static void menu_cancel_cb(lv_event_t* e) {
	(void)e;
	navigate_back(SCREEN_SETTINGS);
}

static void update_status_labels(wifi_screen_state_t* state) {
	char buf[128];
	if (network_is_connected()) {
		int rssi = network_get_rssi();
		if (rssi != 0) {
			const char* quality;
			if (rssi >= -50) {
				quality = "Excellent";
			} else if (rssi >= -60) {
				quality = "Good";
			} else if (rssi >= -70) {
				quality = "Fair";
			} else {
				quality = "Weak";
			}
			snprintf(buf, sizeof(buf), "Connected - %s (%d dBm)", quality,
			         rssi);
		} else {
			snprintf(buf, sizeof(buf), "Connected");
		}
	} else {
		snprintf(buf, sizeof(buf), "Not connected");
	}
	lv_label_set_text(state->status_label, buf);
}

ui_state_t setup_wifi_screen(lv_obj_t* parent) {
	wifi_screen_state_t* state = calloc(1, sizeof(wifi_screen_state_t));
	screen_state = state;

	topbar_set_title("WiFi");

	// Status label above the list
	state->status_label = lv_label_create(parent);
	lv_obj_set_width(state->status_label, SCREEN_WIDTH - 8);
	lv_obj_set_pos(state->status_label, 4, TOPBAR_H + 2);
	lv_label_set_long_mode(state->status_label, LV_LABEL_LONG_CLIP);

	// Result label below status
	state->result_label = lv_label_create(parent);
	lv_obj_set_width(state->result_label, SCREEN_WIDTH - 8);
	lv_obj_set_pos(state->result_label, 4, TOPBAR_H + 18);
	lv_label_set_long_mode(state->result_label, LV_LABEL_LONG_CLIP);
	lv_label_set_text(state->result_label, "");

	update_status_labels(state);

	// Show configured networks
	config_t cfg;
	if (config_load(&cfg) && cfg.wifi_count > 0) {
		char buf[128];
		int n = 0;
		for (int i = 0; i < cfg.wifi_count && n < (int)sizeof(buf) - 1; i++) {
			if (i > 0) {
				n += snprintf(buf + n, sizeof(buf) - (size_t)n, ", ");
			}
			n += snprintf(buf + n, sizeof(buf) - (size_t)n, "%s",
			              cfg.wifi[i].ssid);
		}
		lv_label_set_text(state->result_label, buf);
	} else {
		lv_label_set_text(state->result_label, "No config found");
	}

	// Button list below the labels
	state->list = bvs_list_create(parent);
	lv_obj_set_pos(state->list, 0, TOPBAR_H + 34);
	lv_obj_set_size(state->list, SCREEN_WIDTH, SCREEN_HEIGHT - TOPBAR_H - 34);

	lv_obj_t* http_btn = bvs_list_add_nav_button(
	    state->list, NULL, "Test HTTP", test_http_cb, NULL, menu_cancel_cb);

	bvs_list_add_nav_button(state->list, NULL, "Test HTTPS", test_https_cb,
	                        NULL, menu_cancel_cb);

	bvs_list_add_nav_button(state->list, NULL, "Scan Networks", scan_cb, NULL,
	                        menu_cancel_cb);

	bvs_list_add_nav_button(state->list, NULL, "Back", back_event_cb, NULL,
	                        menu_cancel_cb);

	lv_group_focus_obj(http_btn);

	return (ui_state_t){.type = SCREEN_WIFI, .wifi = state};
}

void free_wifi_screen(wifi_screen_state_t* state) {
	if (!state) {
		return;
	}
	network_set_enabled(false);
	screen_state = NULL;
	free(state);
}

void update_wifi_screen(wifi_screen_state_t* state) {
	if (!state) {
		return;
	}

	switch (state->test_phase) {
		case WIFI_TEST_IDLE:
			break;

		case WIFI_TEST_CONNECTING:
			if (!network_set_enabled(true)) {
				lv_label_set_text(state->result_label,
				                  "WiFi connection failed");
				state->test_phase = WIFI_TEST_IDLE;
				break;
			}
			update_status_labels(state);
			state->test_phase = WIFI_TEST_RUNNING;
			break;

		case WIFI_TEST_RUNNING:
			state->test_result = network_test_url(state->test_url);
			state->test_phase = WIFI_TEST_DONE;
			break;

		case WIFI_TEST_DONE: {
			const char* proto = (state->test_url[4] == 's') ? "HTTPS" : "HTTP";
			char buf[64];
			snprintf(buf, sizeof(buf), "%s: %s", proto,
			         state->test_result ? "OK" : "Failed");
			lv_label_set_text(state->result_label, buf);
			network_set_enabled(false);
			update_status_labels(state);
			state->test_phase = WIFI_TEST_IDLE;
			break;
		}

		case WIFI_TEST_SCANNING: {
			char ssids[8][33];
			int count = network_scan(ssids, 8);
			if (count > 0) {
				char buf[256];
				int n = 0;
				for (int i = 0; i < count && n < (int)sizeof(buf) - 1; i++) {
					if (i > 0) {
						n += snprintf(buf + n, sizeof(buf) - (size_t)n, ", ");
					}
					n += snprintf(buf + n, sizeof(buf) - (size_t)n, "%s",
					              ssids[i]);
				}
				lv_label_set_text(state->result_label, buf);
			} else if (count == 0) {
				lv_label_set_text(state->result_label, "No networks found");
			} else {
				char buf[64];
				snprintf(buf, sizeof(buf), "Scan error: %d", count);
				lv_label_set_text(state->result_label, buf);
			}
			state->test_phase = WIFI_TEST_IDLE;
			break;
		}
	}
}