Slide 65 de 74

Uma janela é um serviço

Uma janela, sem tipo de comando
type Model {
	rows:    Str[dyn]
	loading: Bool
}

type Msg {
	Refresh
	Loaded { rows: Str[dyn] }
}

func view(model: Model): ui.View {
	mut ui.View[dyn] kids = [ui.button([ui.on(Msg.Refresh())], "Atualizar")]
	if model.loading {
		append(kids, ui.spinner([]))
	}
	for each row in model.rows {
		append(kids, ui.text([], row))
	}
	return ui.column([ui.pad(24), ui.gap(8)], kids)
}

proc update(model: mut Model, msg: Msg, window: Address): Msg {
	if msg is Msg.Refresh {
		async reload(window)         // lá vai; nada a segurar
		model.loading = true         // ...e o spinner começa agora
	} else if msg is Msg.Loaded(rows) {
		model = Model(rows, false)   // volta como uma mensagem
	}
	return msg
}

proc reload(window: Address): void {
	hive.task.sleep(400)
	async window(Msg.Loaded(["north", "south"]))
}

proc main(): void {
	spawn(ui.window("Colônias", view, update), Model([], false))
}

A mesma árvore, mostrada por uma janela, vira uma interface viva. hive.ui.window(title, view, update) é o handler de um serviço, e spawn a abre com o estado de onde ela começa:

  • view é um func(Model): View — um func, então desenhar nunca pode mudar nada — chamado de novo depois de toda volta.
  • update é um proc(mut Model, Msg): Msg, escrevendo o modelo no lugar para cada evento. Um que recebe um terceiro parâmetro, window: Address, recebe o endereço da própria janela a cada volta. O que ele responde volta para um pedido de outro nó, e é descartado para os eventos da própria janela.
  • Um evento carrega uma mensagem: on(msg) para um clique e onDismiss(msg) para um clique no fundo de um overlay, e uma função que produz uma — como Msg.Changed(_) — para eventos que informam algo: onInput, onSubmit e onChoose uma Str, onToggle um Bool, onSort o índice de uma coluna, e onPick o de uma linha da tabela, sem contar o cabeçalho. Um link numa janela envia sua mensagem em vez de seguir seu href, e uma página servida só mantém um link de caminho, http, https ou mailto.

Abrir uma janela não espera por ela, então um programa pode abrir várias. É uma janela de verdade e não uma aba — uma janela de navegador em modo aplicativo, num perfil próprio, sem nada da sessão ou das extensões de ninguém — e uma máquina sem navegador da família Chromium cai para uma aba. Fechar uma janela mata o serviço dela, fechar a última encerra o programa, e um main que retorna com uma aberta espera por elas.

Uma janela não precisa de tipo de comando para um trabalho que não pode travar a tela: update é um proc, então pode iniciar trabalho com async, e, tendo o próprio endereço, esse trabalho pode mandar a resposta de volta como uma mensagem comum. O ícone do programa é assets/icon.png ao lado do ponto de entrada, um PNG de no máximo 256×256, e a fonte dele é assets/font.woff2: nada no código nomeia nenhum dos dois, a pasta assets/ inteira entra no executável, e no Windows o executável também carrega o ícone, então um gerenciador de arquivos e um atalho fixado o mostram. HIVE_WINDOW=print imprime o endereço da janela, hive-window <url>, em vez de abrir um navegador, para o que for mostrar a página.