Dekajigger the kajiggerlicious SpendTX

This commit is contained in:
Craig Everett 2025-12-23 15:59:48 +09:00
parent d9acde1b83
commit 638c88f900
3 changed files with 152 additions and 153 deletions

View File

@ -38,7 +38,7 @@
accounts = [] :: [gajudesk:poa()], accounts = [] :: [gajudesk:poa()],
picker = none :: none | wx:wx_object(), picker = none :: none | wx:wx_object(),
id = {#w{}, #w{}} :: labeled(), id = {#w{}, #w{}} :: labeled(),
balance = {#w{}, #w{}} :: labeled(), balance = #w{} :: #w{},
buttons = [] :: [widget()], buttons = [] :: [widget()],
history = #h{} :: #h{}}). history = #h{} :: #h{}}).
@ -117,13 +117,9 @@ init(Prefs) ->
_ = wxSizer:add(ID_Sz, ID_L, zxw:flags(base)), _ = wxSizer:add(ID_Sz, ID_L, zxw:flags(base)),
_ = wxSizer:add(ID_Sz, ID_T, zxw:flags(wide)), _ = wxSizer:add(ID_Sz, ID_T, zxw:flags(wide)),
BalanceL = wxStaticText:new(Panel, ?wxID_ANY, ""), BalanceT = wxStaticText:new(Panel, ?wxID_ANY, hz_format:amount(0)),
BalanceT = wxStaticText:new(Panel, ?wxID_ANY, price_to_string(0)), Balance = #w{id = wxStaticText:getId(BalanceT), wx = BalanceT},
Balance =
{#w{id = wxStaticText:getId(BalanceL), wx = BalanceL},
#w{id = wxStaticText:getId(BalanceT), wx = BalanceT}},
BalanceSz = wxBoxSizer:new(?wxHORIZONTAL), BalanceSz = wxBoxSizer:new(?wxHORIZONTAL),
_ = wxSizer:add(BalanceSz, BalanceL, zxw:flags(base)),
_ = wxSizer:add(BalanceSz, BalanceT, zxw:flags(wide)), _ = wxSizer:add(BalanceSz, BalanceT, zxw:flags(wide)),
NumbersSz = wxBoxSizer:new(?wxVERTICAL), NumbersSz = wxBoxSizer:new(?wxVERTICAL),
@ -729,22 +725,16 @@ spend(Selected, State = #s{accounts = Accounts}) ->
end. end.
spend2(#poa{id = ID, name = Name}, Nonce, Height, State = #s{frame = Frame, j = J}) -> spend2(#poa{id = ID, name = Name}, Nonce, Height, State = #s{frame = Frame, j = J}) ->
Title = J("Transfer Gajus"),
Account = [Name, " (", ID, ")"], Account = [Name, " (", ID, ")"],
Args = {Account, Nonce, Height}, Args = {Account, J},
Labels = {J("From"), J("To"), J("Amount"), J("Message (optional)"), J("TTL"), J("Gas Price")},
ok = ok =
case gd_m_spend:show(Frame, Title, Args, Labels) of case gd_m_spend:show(Frame, Args) of
{ok, RecipientID, Amount, GasPrice, TTL, Payload} -> {ok, Partial = #spend_tx{ttl = TTL}} ->
TX = TX =
#spend_tx{sender_id = ID, Partial#spend_tx{sender_id = ID,
recipient_id = RecipientID,
amount = Amount,
gas_price = GasPrice,
gas = 20000, gas = 20000,
ttl = Height + TTL, ttl = Height + TTL,
nonce = Nonce, nonce = Nonce},
payload = Payload},
gd_con:spend(TX); gd_con:spend(TX);
cancel -> cancel ->
ok ok
@ -770,13 +760,13 @@ handle_button(Name, State) ->
do_selection(Selected, do_selection(Selected,
State = #s{prefs = Prefs, accounts = Accounts, State = #s{prefs = Prefs, accounts = Accounts,
balance = {_, #w{wx = B}}, id = {_, #w{wx = I}}}) balance = #w{wx = B}, id = {_, #w{wx = I}}})
when Selected < length(Accounts) -> when Selected < length(Accounts) ->
OneBasedIndex = Selected + 1, OneBasedIndex = Selected + 1,
#poa{id = ID, balances = Balances} = lists:nth(OneBasedIndex, Accounts), #poa{id = ID, balances = Balances} = lists:nth(OneBasedIndex, Accounts),
[#balance{total = Pucks}] = Balances, [#balance{total = Pucks}] = Balances,
ok = wxStaticText:setLabel(I, ID), ok = wxStaticText:setLabel(I, ID),
ok = wxStaticText:setLabel(B, price_to_string(Pucks)), ok = wxStaticText:setLabel(B, hz_format:amount(Pucks)),
ok = gd_con:selected(OneBasedIndex), ok = gd_con:selected(OneBasedIndex),
NewPrefs = maps:put(selected, Selected, Prefs), NewPrefs = maps:put(selected, Selected, Prefs),
State#s{prefs = NewPrefs}; State#s{prefs = NewPrefs};
@ -803,7 +793,7 @@ do_show(Accounts, State = #s{sizer = Sizer, prefs = Prefs, picker = Picker}) ->
ok = wxSizer:layout(Sizer), ok = wxSizer:layout(Sizer),
NewState. NewState.
clear_account(State = #s{balance = {_, #w{wx = B}}, id = {_, #w{wx = I}}}) -> clear_account(State = #s{balance = #w{wx = B}, id = {_, #w{wx = I}}}) ->
ok = wxStaticText:setLabel(I, ""), ok = wxStaticText:setLabel(I, ""),
ok = wxStaticText:setLabel(B, ""), ok = wxStaticText:setLabel(B, ""),
State. State.

View File

@ -4,7 +4,7 @@
%%% Interprets [ENTER] as an "OK" button click and [ESC] as a "Cancel" button click. %%% Interprets [ENTER] as an "OK" button click and [ESC] as a "Cancel" button click.
%%% @end %%% @end
-module(gd_m_wallet_importer). -module(gd_m_spend).
-vsn("0.8.0"). -vsn("0.8.0").
-author("Craig Everett <zxq9@zxq9.com>"). -author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>"). -copyright("Craig Everett <zxq9@zxq9.com>").
@ -12,7 +12,7 @@
-behavior(zxw_modal). -behavior(zxw_modal).
-export([show/6]). -export([show/2]).
-export([init/1, handle_info/2, handle_event/2]). -export([init/1, handle_info/2, handle_event/2]).
-include_lib("wx/include/wx.hrl"). -include_lib("wx/include/wx.hrl").
@ -23,145 +23,139 @@
{frame = none :: none | wx:wx_object(), {frame = none :: none | wx:wx_object(),
parent = none :: none | wx:wx_object(), parent = none :: none | wx:wx_object(),
caller = none :: none | pid(), caller = none :: none | pid(),
j = j() :: fun(),
to_tx = none :: none | wx:wx_object(), to_tx = none :: none | wx:wx_object(),
amount_tx = none :: none | wx:wx_object(), amount_tx = none :: none | wx:wx_object(),
payload_tx = none :: none | wx:wx_object(), payload_tx = none :: none | wx:wx_object(),
ttl_sl = none :: none | wx:wx_object(), ttl_sl = none :: none | wx:wx_object(),
gas_sl = none :: none | wx:wx_object(), gas_sl = none :: none | wx:wx_object(),
ok = none :: none | wx:wx_object(), affirm = none :: none | wx:wx_object(),
cancel = none :: none | wx:wx_object()}). cancel = none :: none | wx:wx_object()}).
j() ->
fun(X) -> X end.
%%% Interface %%% Interface
-spec show(Parent, Title, Args, Labels) -> {ok, ReceipientID, Amount, GasPrice, TTL, Payload} | cancel -spec show(Parent, Args) -> {ok, #spend_tx{}} | cancel
when Parent :: wxFrame:wxFrame(), when Parent :: wxFrame:wxFrame(),
Title :: string(),
Args :: {Account :: iolist(), Args :: {Account :: iolist(),
Nonce :: pos_integer(), Nonce :: pos_integer(),
Height :: pos_integer()}, Height :: pos_integer(),
Labels :: {FromL :: string(), J :: fun()}.
ToL :: string(),
AmountL :: string(),
MessageL :: string(),
TTL_L :: string(),
GasL :: string(),
AffirmL :: string(),
CancelL :: string()},
RecipientID :: binary(), % <<"ak_...">> | <<"ct_...">>
Amount :: non_neg_integer(), % Pucks
GasPrice :: pos_integer(), % Pucks
TTL :: non_neg_integer(), % Generations
Payload :: binary().
show(Parent, Title, Args, Labels) -> show(Parent, Args) ->
zxw_modal:show(Parent, ?MODULE, {Title, Args, Labels}). zxw_modal:show(Parent, ?MODULE, Args).
%% Init %% Init
init({Parent, Caller, {Title, Args, Labels}}) -> init({Parent, Caller, {Account, J}}) ->
{Account, Nonce, Height} = Args, Frame = wxFrame:new(Parent, ?wxID_ANY, J("Transfer Gajus")),
{FromL, ToL, AmountL, MessageL, TTL_L, GasL, AffirmL, CancelL} = Labels,
Frame = wxFrame:new(Parent, ?wxID_ANY, Title),
Panel = wxWindow:new(Frame, ?wxID_ANY), Panel = wxWindow:new(Frame, ?wxID_ANY),
TopSz = wxBoxSizer:new(?wxVERTICAL), TopSz = wxBoxSizer:new(?wxVERTICAL),
_ = wxBoxSizer:add(TopSz, Panel, zxw:flags(wide)), _ = wxBoxSizer:add(TopSz, Panel, zxw:flags(wide)),
MainSz = wxBoxSizer:new(?wxVERTICAL), MainSz = wxBoxSizer:new(?wxVERTICAL),
FromTx = wxStaticText:new(Panel, ?wxID_ANY, Account), FromTx = wxStaticText:new(Panel, ?wxID_ANY, Account),
FromSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, FromL}]), FromSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, J("From")}]),
_ = wxStaticBoxSizer:add(FromSz, FromTx, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(FromSz, FromTx, zxw:flags({wide, 5})),
ToTx = wxTextCtrl:new(Panel, ?wxID_ANY), ToTx = wxTextCtrl:new(Panel, ?wxID_ANY),
ToSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, ToL}]), ToSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, J("To")}]),
_ = wxStaticBoxSizer:add(ToSz, ToTx, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(ToSz, ToTx, zxw:flags({wide, 5})),
AmtTx = wxTextCtrl:new(Panel, ?wxID_ANY), AmtTx = wxTextCtrl:new(Panel, ?wxID_ANY),
AmtSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, AmountL}]), AmtSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, J("Amount")}]),
AmtInSz = wxBoxSizer:new(?wxHORIZONTAL), AmtInSz = wxBoxSizer:new(?wxHORIZONTAL),
AmtLabel = wxStaticText:new(Panel, ?wxID_ANY, ""), AmtLabel = wxStaticText:new(Panel, ?wxID_ANY, ""),
_ = wxStaticBoxSizer:add(AmtInSz, AmtLabel, zxw:flags(base)), _ = wxStaticBoxSizer:add(AmtInSz, AmtLabel, zxw:flags(base)),
_ = wxStaticBoxSizer:add(AmtInSz, AmtTx, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(AmtInSz, AmtTx, zxw:flags({wide, 5})),
_ = wxStaticBoxSizer:add(AmtSz, AmtInSz, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(AmtSz, AmtInSz, zxw:flags({wide, 5})),
PayloadTx = wxTextCtrl:new(Panel, ?wxID_ANY, [{style, ?wxTE_MULTILINE}]), PayloadTx = wxTextCtrl:new(Panel, ?wxID_ANY, [{style, ?wxTE_MULTILINE}]),
PayloadSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, MessageL}]), PayloadSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, J("Message")}]),
_ = wxStaticBoxSizer:add(PayloadSz, PayloadTx, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(PayloadSz, PayloadTx, zxw:flags({wide, 5})),
Style = [{style, ?wxSL_HORIZONTAL bor ?wxSL_LABELS}], Style = [{style, ?wxSL_HORIZONTAL bor ?wxSL_LABELS}],
TTL_Sl = wxSlider:new(Panel, ?wxID_ANY, 100, 10, 1000, Style), TTL_Sl = wxSlider:new(Panel, ?wxID_ANY, 100, 10, 1000, Style),
TTL_Sz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, TTL_L}]), TTL_Sz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, J("TTL")}]),
_ = wxStaticBoxSizer:add(TTL_Sz, TTL_Sl, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(TTL_Sz, TTL_Sl, zxw:flags({wide, 5})),
Min = hz:min_gas_price(), Min = hz:min_gas_price(),
Max = Min * 2, Max = Min * 2,
GasSl = wxSlider:new(Panel, ?wxID_ANY, Min, Min, Max, Style), GasSl = wxSlider:new(Panel, ?wxID_ANY, Min, Min, Max, Style),
GasSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, GasL}]), GasSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, J("Gas Price")}]),
_ = wxStaticBoxSizer:add(GasSz, GasSl, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(GasSz, GasSl, zxw:flags({wide, 5})),
ButtSz = wxBoxSizer:new(?wxHORIZONTAL), ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
Affirm = wxButton:new(Panel, ?wxID_ANY, [{label, AffirmL}]), Affirm = wxButton:new(Panel, ?wxID_ANY, [{label, J("OK")}]),
Cancel = wxButton:new(Panel, ?wxID_ANY, [{label, CancelL}]), Cancel = wxButton:new(Panel, ?wxID_ANY, [{label, J("Cancel")}]),
_ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags({wide, 5})), _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags({wide, 5})),
_ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags({wide, 5})), _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags({wide, 5})),
_ = wxBoxSizer:add(MainSz, FromSz, zxw:flags({base, 5})), _ = wxBoxSizer:add(MainSz, FromSz, zxw:flags({base, 5})),
_ = wxBoxSizer:add(MainSz, ToSz, zxw:flags({base, 5})), _ = wxBoxSizer:add(MainSz, ToSz, zxw:flags({base, 5})),
_ = wxBoxSizer:add(MainSz, AmtSz, zxw:flags({base, 5})), _ = wxBoxSizer:add(MainSz, AmtSz, zxw:flags({base, 5})),
_ = wxBoxSizer:add(MainSz, PayloadSz, zxw:flags({wide, 5})), _ = wxBoxSizer:add(MainSz, PayloadSz, zxw:flags({wide, 5})),
_ = wxBoxSizer:add(MainSz, TTL_Sz, zxw:flags({wide, 5})), _ = wxBoxSizer:add(MainSz, TTL_Sz, zxw:flags({base, 5})),
_ = wxBoxSizer:add(MainSz, GasSz, zxw:flags({base, 5})), _ = wxBoxSizer:add(MainSz, GasSz, zxw:flags({base, 5})),
_ = wxBoxSizer:add(MainSz, ButtSz, zxw:flags({base, 5})), _ = wxBoxSizer:add(MainSz, ButtSz, zxw:flags({base, 5})),
HandleKey = key_handler(ToTx, AmtTx, PayloadTx, TTL_Sl, GasSl, OK, Cancel), HandleKey = key_handler(ToTx, AmtTx, PayloadTx, TTL_Sl, GasSl, Affirm, Cancel),
ok = wxFrame:connect(Frame, key_down, [{callback, HandleKey}]), ok = wxFrame:connect(Frame, key_down, [{callback, HandleKey}]),
ok = wxTextCtrl:connect(ToTx, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(ToTx, key_down, [{callback, HandleKey}]),
ok = wxTextCtrl:connect(AmtTx, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(AmtTx, key_down, [{callback, HandleKey}]),
ok = wxTextCtrl:connect(PayloadTx, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(PayloadTx, key_down, [{callback, HandleKey}]),
ok = wxTextCtrl:connect(TTL_Sl, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(TTL_Sl, key_down, [{callback, HandleKey}]),
ok = wxTextCtrl:connect(GasSl, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(GasSl, key_down, [{callback, HandleKey}]),
ok = wxTextCtrl:connect(OK, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(Affirm, key_down, [{callback, HandleKey}]),
ok = wxTextCtrl:connect(Cancel, key_down, [{callback, HandleKey}]), ok = wxTextCtrl:connect(Cancel, key_down, [{callback, HandleKey}]),
ok = wxFrame:connect(Frame, command_button_clicked), ok = wxFrame:connect(Frame, command_button_clicked),
ok = wxFrame:connect(Frame, close_window), ok = wxFrame:connect(Frame, close_window),
ok = wxFrame:setSize(Frame, {500, 450}), ok = wxFrame:setSize(Frame, {500, 650}),
ok = wxFrame:center(Frame), ok = wxFrame:center(Frame),
ok = wxWindow:setSizer(Panel, MainSz), ok = wxWindow:setSizer(Panel, MainSz),
ok = wxFrame:setSizer(Frame, TopSz), ok = wxFrame:setSizer(Frame, TopSz),
ok = wxBoxSizer:layout(MainSz), ok = wxBoxSizer:layout(MainSz),
ok = wxFrame:centerOnParent(Frame), ok = wxFrame:centerOnParent(Frame),
ok = wxTextCtrl:setFocus(NameTx),
true = wxFrame:show(Frame), true = wxFrame:show(Frame),
self() ! {tab, cancel},
State = State =
#s{frame = Frame, parent = Parent, caller = Caller, #s{frame = Frame, parent = Parent, caller = Caller,
to_tx = ToTx, amount_tx = AmtTx, payload_tx = PayloadTx, to_tx = ToTx, amount_tx = AmtTx, payload_tx = PayloadTx,
ttl_sl = TTL_Sl, gas_sl = GasSl, ttl_sl = TTL_Sl, gas_sl = GasSl,
ok = OK, cancel = Cancel}, affirm = Affirm, cancel = Cancel},
{Frame, State}. {Frame, State}.
key_handler(ToTx, AmtTx, PayloadTx, TTL_Sl, GasSl, OK, Cancel) -> key_handler(ToTx, AmtTx, PayloadTx, TTL_Sl, GasSl, Affirm, Cancel) ->
Me = self(), Me = self(),
ToID = wxTextCtrl:getId(ToTx), ToID = wxTextCtrl:getId(ToTx),
AmtID = wxTextCtrl:getId(AmtTx), AmtID = wxTextCtrl:getId(AmtTx),
PL_ID = wxTextCtrl:getId(PayloadTx), PL_ID = wxTextCtrl:getId(PayloadTx),
TTL_ID = wxSlider:getId(TTL_Sl), TTL_ID = wxSlider:getId(TTL_Sl),
GasID = wxSlider:getId(GasSl), GasID = wxSlider:getId(GasSl),
OK_ID = wxButton:getId(OK), AffirmID = wxButton:getId(Affirm),
CancelID = wxButton:getId(Cancel), CancelID = wxButton:getId(Cancel),
fun(#wx{id = ID, event = #wxKey{type = key_down, keyCode = Code}}, KeyPress) -> fun(#wx{id = ID, event = #wxKey{type = key_down, keyCode = Code}}, KeyPress) ->
case Code of case Code of
% 9 -> 9 ->
% case ID of case ID of
% ToID -> Me ! {tab, to_tx}; ToID -> Me ! {tab, to_tx};
% AmtID -> Me ! {tab, amount_tx}; AmtID -> Me ! {tab, amount_tx};
% PL_ID -> Me ! {tab, payload_tx}; PL_ID -> Me ! {tab, payload_tx};
% TTL_ID -> Me ! {tab, ttl_sl}; TTL_ID -> Me ! {tab, ttl_sl};
% GasID -> Me ! {tab, gas_sl}; GasID -> Me ! {tab, gas_sl};
% OK_ID -> Me ! {tab, ok}; AffirmID -> Me ! {tab, affirm};
% CancelID -> Me ! {tab, cancel}; CancelID -> Me ! {tab, cancel};
% _ -> wxEvent:skip(KeyPress) _ -> wxEvent:skip(KeyPress)
% end; end;
% 13 -> 13 ->
% case ID of case ID of
% NameID -> Me ! {enter, name}; ToID -> Me ! {tab, to_tx};
% PassID -> Me ! {enter, pass}; AmtID -> Me ! {tab, amount_tx};
% _ -> wxEvent:skip(KeyPress) PL_ID -> Me ! {tab, payload_tx};
% end; TTL_ID -> Me ! {tab, ttl_sl};
GasID -> Me ! {tab, gas_sl};
AffirmID -> Me ! {enter, affirm};
CancelID -> Me ! {enter, cancel};
_ -> wxEvent:skip(KeyPress)
end;
27 -> 27 ->
Me ! esc; Me ! esc;
_ -> _ ->
@ -174,11 +168,11 @@ key_handler(ToTx, AmtTx, PayloadTx, TTL_Sl, GasSl, OK, Cancel) ->
handle_info({tab, Element}, State) -> handle_info({tab, Element}, State) ->
ok = tab_traverse(Element, State), ok = tab_traverse(Element, State),
{noreply, State}; {noreply, State};
handle_info({enter, name}, State = #s{pass_tx = PassTx}) -> handle_info({enter, affirm}, State) ->
ok = wxTextCtrl:setFocus(PassTx), NewState = check(State),
{noreply, State}; {noreply, NewState};
handle_info({enter, pass}, State) -> handle_info({enter, cancel}, State) ->
done(State); cancel(State);
handle_info(esc, State) -> handle_info(esc, State) ->
ok = cancel(State), ok = cancel(State),
{noreply, State}; {noreply, State};
@ -188,13 +182,15 @@ handle_info(Message, State) ->
handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID},
State = #s{ok = OK, cancel = Cancel}) -> State = #s{affirm = Affirm, cancel = Cancel}) ->
OK_ID = wxButton:getId(OK), AffirmID = wxButton:getId(Affirm),
CancelID = wxButton:getId(Cancel), CancelID = wxButton:getId(Cancel),
NewState =
case ID of case ID of
OK_ID -> done(State); AffirmID -> check(State);
CancelID -> cancel(State) CancelID -> cancel(State)
end; end,
{noreply, NewState};
handle_event(#wx{event = #wxClose{}}, State) -> handle_event(#wx{event = #wxClose{}}, State) ->
NewState = cancel(State), NewState = cancel(State),
{noreply, NewState}; {noreply, NewState};
@ -205,14 +201,20 @@ handle_event(Event, State) ->
%%% Doers %%% Doers
%tab_traverse(name, #s{pass_tx = PassTx}) -> tab_traverse(to_tx, #s{amount_tx = AmountTX}) ->
% wxTextCtrl:setFocus(PassTx); wxTextCtrl:setFocus(AmountTX);
%tab_traverse(pass, #s{ok = OK}) -> tab_traverse(amount_tx, #s{payload_tx = PayloadTX}) ->
% wxButton:setFocus(OK); wxTextCtrl:setFocus(PayloadTX);
%tab_traverse(ok, #s{cancel = Cancel}) -> tab_traverse(payload_tx, #s{ttl_sl = TTL_SL}) ->
% wxButton:setFocus(Cancel); wxSlider:setFocus(TTL_SL);
%tab_traverse(cancel, #s{name_tx = NameTx}) -> tab_traverse(ttl_sl, #s{gas_sl = GasSL}) ->
% wxTextCtrl:setFocus(NameTx). wxSlider:setFocus(GasSL);
tab_traverse(gas_sl, #s{affirm = Affirm}) ->
wxButton:setFocus(Affirm);
tab_traverse(affirm, #s{cancel = Cancel}) ->
wxButton:setFocus(Cancel);
tab_traverse(cancel, #s{to_tx = ToTX}) ->
wxTextCtrl:setFocus(ToTX).
cancel(#s{frame = Frame, caller = Caller}) -> cancel(#s{frame = Frame, caller = Caller}) ->
@ -220,56 +222,63 @@ cancel(#s{frame = Frame, caller = Caller}) ->
zxw_modal:done(Caller, cancel). zxw_modal:done(Caller, cancel).
done(#s{frame = Frame, caller = Caller, check(State =#s{frame = Frame, caller = Caller, j = J,
to_tx = ToTx, amount_tx = AmountTx, payload_tx = PayloadTx, to_tx = ToTx, amount_tx = AmountTx, payload_tx = PayloadTx,
ttl_sl = TTL_Sl, gas_sl = GasSl}) -> ttl_sl = TTL_Sl, gas_sl = GasSl}) ->
DirtyTX = DirtyTX =
#spend_tx{recipient_id = wxTextCtrl:getValue(ToTx), [{recipient_id, wxTextCtrl:getValue(ToTx)},
amount = wxTextCtrl:getValue(AmountTx), {amount, wxTextCtrl:getValue(AmountTx)},
gas_price = wxSlider:getValue(GasSl), {gas_price, wxSlider:getValue(GasSl)},
ttl = wxSlider:getValue(TTL_Sl), {ttl, wxSlider:getValue(TTL_Sl)},
payload = wxTextCtrl:getValue(PayloadTX)}, {payload, wxTextCtrl:getValue(PayloadTx)}],
Result = ok =
case clean_spend(TX) of case clean_spend(DirtyTX, #spend_tx{}, J, []) of
{ok, CleanTX} -> {ok, CleanTX} ->
zxw_modal:done(Caller, {ok, CleanTX});
{error, Errors} ->
DerpyDerpDerp = form_message(Errors, J),
ok = zxw:show_message(Frame, DerpyDerpDerp),
State
end.
% TODO: There should be some suggestive logic around gas prices, both based on how large
% the payload and TTL are, but also the ingoing current common gas rate. This will require
% a "gas station" sort of analysis app to query, though.
clean_spend([{recipient_id, ""} | Rest], TX, J, Errors) ->
NewErrors = [{recipient_id, J("Recipient field is empty.")} | Errors],
clean_spend(Rest, TX, J, NewErrors);
clean_spend([{recipient_id, Recipient} | Rest], TX, J, Errors) ->
clean_spend(Rest, TX#spend_tx{recipient_id = list_to_binary(Recipient)}, J, Errors);
clean_spend([{amount, ""} | Rest], TX, J, Errors) ->
clean_spend(Rest, TX#spend_tx{amount = 0}, J, Errors);
clean_spend([{amount, S} | Rest], TX, J, Errors) ->
{NewTX, NewErrors} =
case hz_format:read(S) of
{ok, Amount} ->
{TX#spend_tx{amount = Amount}, Errors};
error ->
Derp = J("Amount field is not properly formatted."),
{TX, [{amount, Derp} | Errors]}
end, end,
Result = clean_spend(Rest, NewTX, J, NewErrors);
case wxTextCtrl:getValue(NameTx) of clean_spend([{gas_price, GasPrice} | Rest], TX, J, Errors) ->
"" -> clean_spend(Rest, TX#spend_tx{gas_price = GasPrice}, J, Errors);
cancel; clean_spend([{ttl, TTL} | Rest], TX, J, Errors) ->
Name -> clean_spend(Rest, TX#spend_tx{ttl = TTL}, J, Errors);
case wxTextCtrl:getValue(PassTx) of clean_spend([{payload = S} | Rest], TX, J, Errors) ->
"" -> {ok, Name, none}; clean_spend(Rest, TX#spend_tx{payload = list_to_binary(S)}, J, Errors);
Pass -> {ok, Name, Pass} clean_spend([], TX, _, []) ->
end {ok, TX};
end, clean_spend([], _, _, Errors) ->
ok = wxFrame:destroy(Frame), {error, Errors}.
zxw_modal:done(Caller, Result).
clean_spend(TX) ->
clean_spend(TX, []).
clean_spend(TX = #spend_tx{recipient_id = ""}, Errors) ->
clean_spend(TX#spend_tx{recipient_id = none}, [recipient_id | Errors]);
clean_spend(TX = #spend_tx{amount = S}, Errors) when is_list(S) ->
case string_to_price(S) of
{ok, Amount} -> clean_spend(TX#spend_tx{amount = Amount});
{error, _} -> ok
end;
clean_spend(TX = #spend_tx{gas_price = S}) when is_list(S) ->
case is_int(S) of
true -> clean_spend(TX#spend_tx{gas_price = list_to_integer(S)});
false -> ok
end;
clean_spend(TX = #spend_tx{gas = S}) when is_list(S) ->
case is_int(S) of
true -> clean_spend(TX#spend_tx{gas = list_to_integer(S)});
false -> ok
end;
clean_spend(TX = #spend_tx{payload = S}) when is_list(S) ->
clean_spend(TX#spend_tx{payload = list_to_binary(S)});
clean_spend(TX) ->
{ok, CleanTX}.
form_message(Errors, J) ->
Header = J("The following errors were encountered:"),
unicode:characters_to_list([Header, "\n", assemble(Errors)]).
% TODO: Highlight the fields since we know them.
assemble([{_, M} | T]) -> [M, "\n" | assemble(T)];
assemble([]) -> [].

View File

@ -5,8 +5,8 @@
{author,"Craig Everett"}. {author,"Craig Everett"}.
{desc,"A desktop client for the Gajumaru network of blockchain networks"}. {desc,"A desktop client for the Gajumaru network of blockchain networks"}.
{package_id,{"otpr","gajudesk",{0,8,0}}}. {package_id,{"otpr","gajudesk",{0,8,0}}}.
{deps,[{"otpr","zxwidgets",{1,1,0}}, {deps,[{"otpr","hakuzaru",{0,8,2}},
{"otpr","hakuzaru",{0,7,0}}, {"otpr","zxwidgets",{1,1,0}},
{"otpr","eblake2",{1,0,1}}, {"otpr","eblake2",{1,0,1}},
{"otpr","base58",{0,1,1}}, {"otpr","base58",{0,1,1}},
{"otpr","gmserialization",{0,1,3}}, {"otpr","gmserialization",{0,1,3}},