nd,ngui: let users switch sysupdates channel from the UI
at the moment, there are two channels: edge and stable. this builds up on few previous commits, most notably the persistent configuration storage.pull/28/head v0.5.0
parent
1d8d67a987
commit
c82848d186
@ -0,0 +1,131 @@
|
|||||||
|
//! settings main tab.
|
||||||
|
//! all functions assume LVGL is init'ed and ui mutex is locked on entry.
|
||||||
|
//!
|
||||||
|
//! TODO: at the moment, most of the code is still in C; need to port to zig from src/ui/c/ui.c
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const comm = @import("../comm.zig");
|
||||||
|
const lvgl = @import("lvgl.zig");
|
||||||
|
const symbol = @import("symbol.zig");
|
||||||
|
|
||||||
|
const logger = std.log.scoped(.ui);
|
||||||
|
|
||||||
|
/// label color mark start to make "label:" part of a "label: value"
|
||||||
|
/// in a different color.
|
||||||
|
const cmark = "#bbbbbb ";
|
||||||
|
/// button text
|
||||||
|
const textSwitch = "SWITCH";
|
||||||
|
|
||||||
|
/// the settings tab alive for the whole duration of the process.
|
||||||
|
var tab: struct {
|
||||||
|
sysupdates: struct {
|
||||||
|
card: lvgl.Card,
|
||||||
|
chansel: lvgl.Dropdown,
|
||||||
|
switchbtn: lvgl.TextButton,
|
||||||
|
currchan: lvgl.Label,
|
||||||
|
},
|
||||||
|
} = undefined;
|
||||||
|
|
||||||
|
/// holds last values received from the daemon.
|
||||||
|
var state: struct {
|
||||||
|
curr_sysupdates_chan: ?comm.Message.SysupdatesChan = null,
|
||||||
|
} = .{};
|
||||||
|
|
||||||
|
/// creates a settings panel UI to control system updates channel.
|
||||||
|
/// must be called only once at program startup.
|
||||||
|
pub fn initSysupdatesPanel(cont: lvgl.Container) !lvgl.Card {
|
||||||
|
tab.sysupdates.card = try lvgl.Card.new(cont, symbol.Loop ++ " SYSUPDATES", .{ .spinner = true });
|
||||||
|
const l1 = try lvgl.Label.new(tab.sysupdates.card, "" //
|
||||||
|
++ "https://git.qcode.ch/nakamochi/sysupdates " // TODO: make this configurable?
|
||||||
|
++ "is the source of system updates.", .{});
|
||||||
|
l1.setPad(15, .top, .{});
|
||||||
|
l1.setWidth(lvgl.sizePercent(100));
|
||||||
|
l1.setHeightToContent();
|
||||||
|
|
||||||
|
const row = try lvgl.FlexLayout.new(tab.sysupdates.card, .row, .{});
|
||||||
|
row.setWidth(lvgl.sizePercent(100));
|
||||||
|
row.setHeightToContent();
|
||||||
|
|
||||||
|
// left column
|
||||||
|
const left = try lvgl.FlexLayout.new(row, .column, .{});
|
||||||
|
left.flexGrow(1);
|
||||||
|
left.setPad(10, .row, .{});
|
||||||
|
left.setHeightToContent();
|
||||||
|
tab.sysupdates.currchan = try lvgl.Label.new(left, cmark ++ "CURRENT CHANNEL:# unknown", .{ .recolor = true });
|
||||||
|
tab.sysupdates.currchan.setHeightToContent();
|
||||||
|
const lab = try lvgl.Label.new(left, "edge channel may contain some experimental and unstable features.", .{});
|
||||||
|
lab.setWidth(lvgl.sizePercent(100));
|
||||||
|
lab.setHeightToContent();
|
||||||
|
|
||||||
|
// right column
|
||||||
|
const right = try lvgl.FlexLayout.new(row, .column, .{});
|
||||||
|
right.flexGrow(1);
|
||||||
|
right.setPad(10, .row, .{});
|
||||||
|
right.setHeightToContent();
|
||||||
|
tab.sysupdates.chansel = try lvgl.Dropdown.newStatic(right, blk: {
|
||||||
|
// items order must match that of the switch in update fn.
|
||||||
|
break :blk @tagName(comm.Message.SysupdatesChan.stable) // index 0
|
||||||
|
++ "\n" ++ @tagName(comm.Message.SysupdatesChan.edge); // index 1
|
||||||
|
});
|
||||||
|
tab.sysupdates.chansel.setWidth(lvgl.sizePercent(100));
|
||||||
|
tab.sysupdates.chansel.setText(""); // show no pre-selected value
|
||||||
|
_ = tab.sysupdates.chansel.on(.value_changed, nm_sysupdates_chansel_changed, null);
|
||||||
|
tab.sysupdates.switchbtn = try lvgl.TextButton.new(right, textSwitch);
|
||||||
|
tab.sysupdates.switchbtn.setWidth(lvgl.sizePercent(100));
|
||||||
|
// disable channel switch button 'till data received from the daemon
|
||||||
|
// or user-selected value.
|
||||||
|
tab.sysupdates.switchbtn.disable();
|
||||||
|
_ = tab.sysupdates.switchbtn.on(.click, nm_sysupdates_switch_click, null);
|
||||||
|
|
||||||
|
return tab.sysupdates.card;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// updates the UI with the data from the provided settings arg.
|
||||||
|
pub fn update(sett: comm.Message.Settings) !void {
|
||||||
|
var buf: [512]u8 = undefined;
|
||||||
|
try tab.sysupdates.currchan.setTextFmt(&buf, cmark ++ "CURRENT CHANNEL:# {s}", .{@tagName(sett.sysupdates.channel)});
|
||||||
|
state.curr_sysupdates_chan = sett.sysupdates.channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn nm_sysupdates_chansel_changed(_: *lvgl.LvEvent) void {
|
||||||
|
var buf = [_]u8{0} ** 32;
|
||||||
|
const name = tab.sysupdates.chansel.getSelectedStr(&buf);
|
||||||
|
const chan = std.meta.stringToEnum(comm.Message.SysupdatesChan, name) orelse return;
|
||||||
|
if (state.curr_sysupdates_chan) |curr_chan| {
|
||||||
|
if (chan != curr_chan) {
|
||||||
|
tab.sysupdates.switchbtn.enable();
|
||||||
|
tab.sysupdates.chansel.clearText(); // show selected value
|
||||||
|
} else {
|
||||||
|
tab.sysupdates.switchbtn.disable();
|
||||||
|
tab.sysupdates.chansel.setText(""); // hide selected value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tab.sysupdates.switchbtn.enable();
|
||||||
|
tab.sysupdates.chansel.clearText(); // show selected value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn nm_sysupdates_switch_click(_: *lvgl.LvEvent) void {
|
||||||
|
var buf = [_]u8{0} ** 32;
|
||||||
|
const name = tab.sysupdates.chansel.getSelectedStr(&buf);
|
||||||
|
switchSysupdates(name) catch |err| logger.err("switchSysupdates: {any}", .{err});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn switchSysupdates(name: []const u8) !void {
|
||||||
|
const chan = std.meta.stringToEnum(comm.Message.SysupdatesChan, name) orelse return error.InvalidSysupdateChannel;
|
||||||
|
logger.debug("switching sysupdates to channel {}", .{chan});
|
||||||
|
|
||||||
|
tab.sysupdates.switchbtn.disable();
|
||||||
|
tab.sysupdates.switchbtn.label.setTextStatic("UPDATING ...");
|
||||||
|
tab.sysupdates.chansel.disable();
|
||||||
|
tab.sysupdates.card.spin(.on);
|
||||||
|
errdefer {
|
||||||
|
tab.sysupdates.card.spin(.off);
|
||||||
|
tab.sysupdates.chansel.enable();
|
||||||
|
tab.sysupdates.switchbtn.enable();
|
||||||
|
tab.sysupdates.switchbtn.label.setTextStatic(textSwitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
try comm.pipeWrite(.{ .switch_sysupdates = chan });
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
///! see lv_symbols_def.h
|
///! see lv_symbols_def.h
|
||||||
|
pub const Loop = &[_]u8{ 0xef, 0x81, 0xb9 };
|
||||||
pub const Ok = &[_]u8{ 0xef, 0x80, 0x8c };
|
pub const Ok = &[_]u8{ 0xef, 0x80, 0x8c };
|
||||||
pub const Power = &[_]u8{ 0xef, 0x80, 0x91 };
|
pub const Power = &[_]u8{ 0xef, 0x80, 0x91 };
|
||||||
pub const Warning = &[_]u8{ 0xef, 0x81, 0xb1 };
|
pub const Warning = &[_]u8{ 0xef, 0x81, 0xb1 };
|
||||||
|
Reference in New Issue