WIP: Adding config interface
This commit is contained in:
parent
bccabcb1c0
commit
f901ba6c9d
@ -30,8 +30,10 @@
|
|||||||
exec_dir = platform_dir() :: file:filename(),
|
exec_dir = platform_dir() :: file:filename(),
|
||||||
acc = none :: none | binary(),
|
acc = none :: none | binary(),
|
||||||
keys = [] :: [],
|
keys = [] :: [],
|
||||||
mem_limit = 3550722201 :: pos_integer(),
|
max_cores = 2 :: pos_integer(),
|
||||||
prefs = #{} :: #{}}).
|
max_mem = 3550722201 :: pos_integer(),
|
||||||
|
prefs = #{} :: #{},
|
||||||
|
gmc_conf = none :: none | reference()}).
|
||||||
|
|
||||||
-type state() :: #s{}.
|
-type state() :: #s{}.
|
||||||
|
|
||||||
@ -51,19 +53,18 @@ gajudesk() ->
|
|||||||
gen_server:cast(?MODULE, gajudesk).
|
gen_server:cast(?MODULE, gajudesk).
|
||||||
|
|
||||||
|
|
||||||
-spec conf() -> {Account, Keys, Network}
|
-spec conf() -> ok.
|
||||||
when Account :: none | binary(), % <<"ak_...">>
|
|
||||||
Keys :: [binary()],
|
|
||||||
Network :: binary(). % <<"mainnet">> | <<"testnet">> | <<"devnet">>
|
|
||||||
|
|
||||||
conf() ->
|
conf() ->
|
||||||
gen_server:call(?MODULE, conf).
|
gen_server:cast(?MODULE, conf).
|
||||||
|
|
||||||
|
|
||||||
-spec conf({Account, Keys, Network}) -> ok
|
-spec conf({Account, Keys, Network, MaxCores, MaxMem}) -> ok
|
||||||
when Account :: none | binary(), % <<"ak_...">>
|
when Account :: none | binary(), % <<"ak_...">>
|
||||||
Keys :: [binary()],
|
Keys :: [binary()], % [<<"ak_...">>]
|
||||||
Network :: binary(). % <<"mainnet">> | <<"testnet">> | <<"devnet">>
|
Network :: binary(), % <<"mainnet">> | <<"testnet">> | <<"devnet">>
|
||||||
|
MaxCores :: none | integer(),
|
||||||
|
MaxMem :: none | integer().
|
||||||
|
|
||||||
conf(Info) ->
|
conf(Info) ->
|
||||||
gen_server:cast(?MODULE, {conf, Info}).
|
gen_server:cast(?MODULE, {conf, Info}).
|
||||||
@ -109,17 +110,18 @@ start_link() ->
|
|||||||
init(none) ->
|
init(none) ->
|
||||||
ok = log(info, "Starting"),
|
ok = log(info, "Starting"),
|
||||||
_ = process_flag(sensitive, true),
|
_ = process_flag(sensitive, true),
|
||||||
{Acc, Keys, Network, MemLimit} =
|
{Acc, Keys, Network, MaxCores, MaxMem} =
|
||||||
case read_conf() of
|
case read_conf() of
|
||||||
{ok, C} ->
|
{ok, C} ->
|
||||||
{maps:get(account, C, none),
|
{maps:get(account, C, none),
|
||||||
maps:get(keys, C, []),
|
maps:get(keys, C, []),
|
||||||
maps:get(network, C, <<"mainnet">>),
|
maps:get(network, C, <<"mainnet">>),
|
||||||
maps:get(mem_limit, C, 3550722201)};
|
maps:get(max_cores, C, 2),
|
||||||
|
maps:get(max_mem, C, 3550722201)};
|
||||||
none ->
|
none ->
|
||||||
{none, [], <<"mainnet">>, 3550722201}
|
{none, [], <<"mainnet">>, 2, 3550722201}
|
||||||
end,
|
end,
|
||||||
State = #s{network = Network, acc = Acc, keys = Keys, mem_limit = MemLimit},
|
State = #s{network = Network, acc = Acc, keys = Keys, max_cores = MaxCores, max_mem = MaxMem},
|
||||||
{ok, start_gui(State)}.
|
{ok, start_gui(State)}.
|
||||||
|
|
||||||
|
|
||||||
@ -154,8 +156,6 @@ start_gui(State) ->
|
|||||||
|
|
||||||
handle_call(network, _, State = #s{network = Network}) ->
|
handle_call(network, _, State = #s{network = Network}) ->
|
||||||
{reply, Network, State};
|
{reply, Network, State};
|
||||||
handle_call(conf, _, State = #s{acc = Acc, keys = Keys, network = Network}) ->
|
|
||||||
{reply, {Acc, Keys, Network}, State};
|
|
||||||
handle_call(bin_dir, _, State = #s{exec_dir = BinDir}) ->
|
handle_call(bin_dir, _, State = #s{exec_dir = BinDir}) ->
|
||||||
{reply, BinDir, State};
|
{reply, BinDir, State};
|
||||||
handle_call(Unexpected, From, State) ->
|
handle_call(Unexpected, From, State) ->
|
||||||
@ -169,6 +169,12 @@ handle_cast(start_stop, State) ->
|
|||||||
handle_cast(gajudesk, State) ->
|
handle_cast(gajudesk, State) ->
|
||||||
ok = do_gajudesk(),
|
ok = do_gajudesk(),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
|
handle_cast(conf, State) ->
|
||||||
|
NewState = run_gmc_conf(State),
|
||||||
|
{noreply, NewState};
|
||||||
|
handle_cast({conf, Info}, State) ->
|
||||||
|
NewState = do_conf(Info, State),
|
||||||
|
{noreply, NewState};
|
||||||
handle_cast(stop, State) ->
|
handle_cast(stop, State) ->
|
||||||
ok = do_stop(),
|
ok = do_stop(),
|
||||||
ok = log(info, "Received a 'stop' message."),
|
ok = log(info, "Received a 'stop' message."),
|
||||||
@ -181,6 +187,10 @@ handle_cast(Unexpected, State) ->
|
|||||||
handle_info({gproc_ps_event, Event, Data}, State) ->
|
handle_info({gproc_ps_event, Event, Data}, State) ->
|
||||||
ok = gmc_gui:message({Event, Data}),
|
ok = gmc_gui:message({Event, Data}),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
|
handle_info({'DOWN', Mon, process, PID, Info}, State = #s{gmc_conf = Mon}) ->
|
||||||
|
ok = log(info, "gmc_conf ~p closed with ~p", [PID, Info]),
|
||||||
|
NewState = State#s{gmc_conf = none},
|
||||||
|
{noreply, NewState};
|
||||||
handle_info(Unexpected, State) ->
|
handle_info(Unexpected, State) ->
|
||||||
ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]),
|
ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]),
|
||||||
{noreply, State}.
|
{noreply, State}.
|
||||||
@ -211,7 +221,7 @@ do_stop() ->
|
|||||||
|
|
||||||
%%% Doers
|
%%% Doers
|
||||||
|
|
||||||
do_start_stop(#s{acc = PubKey, network = Network, mem_limit = MemLimit}) ->
|
do_start_stop(#s{acc = PubKey, network = Network, max_mem = MaxMem}) ->
|
||||||
% smrt guy stuff happens here
|
% smrt guy stuff happens here
|
||||||
{Bits, Eureka} =
|
{Bits, Eureka} =
|
||||||
case Network of
|
case Network of
|
||||||
@ -238,8 +248,8 @@ do_start_stop(#s{acc = PubKey, network = Network, mem_limit = MemLimit}) ->
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
Miner = unicode:characters_to_binary([Fatness, Bits, "-", Type]),
|
Miner = unicode:characters_to_binary([Fatness, Bits, "-", Type]),
|
||||||
Count = optimize_count(MemLimit),
|
Count = optimize_count(MaxMem),
|
||||||
Instance = #{<<"executable">> => Miner, <<"executable_group">> => <<"gajumine">>},
|
Instance = #{<<"executable">> => Miner},
|
||||||
Workers = lists:duplicate(Count, Instance),
|
Workers = lists:duplicate(Count, Instance),
|
||||||
Profile =
|
Profile =
|
||||||
[{pubkey, PubKey},
|
[{pubkey, PubKey},
|
||||||
@ -260,8 +270,18 @@ do_start_stop(#s{acc = PubKey, network = Network, mem_limit = MemLimit}) ->
|
|||||||
disconnected],
|
disconnected],
|
||||||
lists:foreach(fun gmhc_events:ensure_subscribed/1, Events).
|
lists:foreach(fun gmhc_events:ensure_subscribed/1, Events).
|
||||||
|
|
||||||
optimize_count(MemLimit) ->
|
optimize_count(MaxMem) ->
|
||||||
{Procs, Memory} =
|
{Procs, Memory} = proc_mem(),
|
||||||
|
MeanMaps = min(MaxMem, Memory) div 3550722201,
|
||||||
|
Recommended = max(min(Procs, MeanMaps) - 1, 1),
|
||||||
|
Notice = fun(F, A) -> gmc_gui:message({notice, io_lib:format(F, A)}) end,
|
||||||
|
ok = Notice("Physical Processors: ~p", [Procs]),
|
||||||
|
ok = Notice("Physical Memory: ~p", [Memory]),
|
||||||
|
ok = Notice("29-bit Mean Map Space: ~p", [MeanMaps]),
|
||||||
|
ok = Notice("Workers: ~p", [Recommended]),
|
||||||
|
Recommended.
|
||||||
|
|
||||||
|
proc_mem() ->
|
||||||
case os:type() of
|
case os:type() of
|
||||||
{unix, linux} ->
|
{unix, linux} ->
|
||||||
{processor, Cores} = hd(erlang:system_info(cpu_topology)),
|
{processor, Cores} = hd(erlang:system_info(cpu_topology)),
|
||||||
@ -276,15 +296,7 @@ optimize_count(MemLimit) ->
|
|||||||
P = list_to_integer(os:getenv("NUMBER_OF_PROCESSORS")),
|
P = list_to_integer(os:getenv("NUMBER_OF_PROCESSORS")),
|
||||||
M = list_to_integer(string:strip(lists:nth(2, string:split(os:cmd("wmic computersystem get TotalPhysicalMemory"), "\r\r\n", all)))),
|
M = list_to_integer(string:strip(lists:nth(2, string:split(os:cmd("wmic computersystem get TotalPhysicalMemory"), "\r\r\n", all)))),
|
||||||
{P, M}
|
{P, M}
|
||||||
end,
|
end.
|
||||||
MeanMaps = min(MemLimit, Memory) div 3550722201,
|
|
||||||
Recommended = max(min(Procs, MeanMaps) - 1, 1),
|
|
||||||
Notice = fun(F, A) -> gmc_gui:message({notice, io_lib:format(F, A)}) end,
|
|
||||||
ok = Notice("Physical Processors: ~p", [Procs]),
|
|
||||||
ok = Notice("Physical Memory: ~p", [Memory]),
|
|
||||||
ok = Notice("29-bit Mean Map Space: ~p", [MeanMaps]),
|
|
||||||
ok = Notice("Workers: ~p", [Recommended]),
|
|
||||||
Recommended.
|
|
||||||
|
|
||||||
|
|
||||||
do_gajudesk() ->
|
do_gajudesk() ->
|
||||||
@ -307,13 +319,31 @@ run_gajudesk() ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
run_gmc_conf(State = #s{gmc_conf = none, network = Net, acc = Acc, keys = Keys,
|
||||||
|
max_cores = MProcs, max_mem = MMem,
|
||||||
|
prefs = Prefs}) ->
|
||||||
|
{AProcs, AMem} = proc_mem(),
|
||||||
|
Win = gmc_conf:start_link({Prefs, {Net, Acc, Keys, {AProcs, AMem, MProcs, MMem}}}),
|
||||||
|
PID = wx_object:get_pid(Win),
|
||||||
|
Mon = monitor(process, PID),
|
||||||
|
ok = gmc_conf:to_front(),
|
||||||
|
State#s{gmc_conf = Mon};
|
||||||
|
run_gmc_conf(State) ->
|
||||||
|
ok = gmc_conf:to_front(),
|
||||||
|
State.
|
||||||
|
|
||||||
|
|
||||||
|
do_conf({Network, AccID, Keys, MaxCores, MaxMem}, State) ->
|
||||||
|
State#s{network = Network, acc = AccID, keys = Keys, max_cores = MaxCores, max_mem = MaxMem}.
|
||||||
|
|
||||||
|
|
||||||
%%% Utils
|
%%% Utils
|
||||||
|
|
||||||
|
|
||||||
%% Paths and Names
|
%% Paths and Names
|
||||||
|
|
||||||
persist(#s{network = Network, acc = Acc, keys = Keys, mem_limit = MemLimit, prefs = Prefs}) ->
|
persist(#s{network = Network, acc = Acc, keys = Keys, max_cores = MaxCores, max_mem = MaxMem, prefs = Prefs}) ->
|
||||||
Update = #{network => Network, account => Acc, keys => Keys, mem_limit => MemLimit},
|
Update = #{network => Network, account => Acc, keys => Keys, max_cores => MaxCores, max_mem => MaxMem},
|
||||||
Conf = maps:to_list(maps:merge(Prefs, Update)),
|
Conf = maps:to_list(maps:merge(Prefs, Update)),
|
||||||
Path = gmc_prefs_path(),
|
Path = gmc_prefs_path(),
|
||||||
ok = filelib:ensure_dir(Path),
|
ok = filelib:ensure_dir(Path),
|
||||||
|
249
src/gmc_conf.erl
Normal file
249
src/gmc_conf.erl
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
%%% @doc
|
||||||
|
%%% GajuMine Configuration GUI
|
||||||
|
%%% @end
|
||||||
|
|
||||||
|
-module(gmc_conf).
|
||||||
|
-vsn("0.2.0").
|
||||||
|
-author("Craig Everett <craigeverett@qpq.swiss>").
|
||||||
|
-copyright("Craig Everett <craigeverett@qpq.swiss>").
|
||||||
|
-license("GPL-3.0-or-later").
|
||||||
|
|
||||||
|
-behavior(wx_object).
|
||||||
|
-include_lib("wx/include/wx.hrl").
|
||||||
|
-export([to_front/0, trouble/1]).
|
||||||
|
-export([start_link/1]).
|
||||||
|
-export([init/1, terminate/2, code_change/3,
|
||||||
|
handle_call/3, handle_cast/2, handle_info/2, handle_event/2]).
|
||||||
|
-include("$zx_include/zx_logger.hrl").
|
||||||
|
|
||||||
|
|
||||||
|
-record(s,
|
||||||
|
{wx = none :: none | wx:wx_object(),
|
||||||
|
frame = none :: none | wx:wx_object(),
|
||||||
|
lang = en :: en | jp,
|
||||||
|
j = none :: none | fun(),
|
||||||
|
net = none :: none | wx:wx_object(),
|
||||||
|
acc = none :: none | wx:wx_object(),
|
||||||
|
keys = none :: none | wx:wx_object(),
|
||||||
|
cores = none :: none | wx:wx_object(),
|
||||||
|
memory = none :: none | wx:wx_object()}).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%% Interface functions
|
||||||
|
|
||||||
|
|
||||||
|
-spec to_front() -> ok.
|
||||||
|
|
||||||
|
to_front() ->
|
||||||
|
wx_object:cast(?MODULE, to_front).
|
||||||
|
|
||||||
|
|
||||||
|
-spec trouble(term()) -> ok.
|
||||||
|
|
||||||
|
trouble(Info) ->
|
||||||
|
wx_object:cast(?MODULE, {trouble, Info}).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%% Startup Functions
|
||||||
|
|
||||||
|
start_link(Prefs) ->
|
||||||
|
wx_object:start_link({local, ?MODULE}, ?MODULE, Prefs, []).
|
||||||
|
|
||||||
|
|
||||||
|
init({Prefs, {Net, Acc, Keys, {AProcs, AMem, MProcs, MMem}}}) ->
|
||||||
|
ok = log(info, "GUI starting..."),
|
||||||
|
Lang = maps:get(lang, Prefs, en_US),
|
||||||
|
Trans = gd_jt:read_translations(?MODULE),
|
||||||
|
J = gd_jt:j(Lang, Trans),
|
||||||
|
Label = J("Configure GajuMine"),
|
||||||
|
|
||||||
|
WX = wx:new(),
|
||||||
|
Frame = wxFrame:new(WX, ?wxID_ANY, Label),
|
||||||
|
MainSz = wxBoxSizer:new(?wxVERTICAL),
|
||||||
|
|
||||||
|
AccSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("GajuMining Account ID")}]),
|
||||||
|
AccTx = wxTextCtrl:new(Frame, ?wxID_ANY, [{value, acc(Acc)}]),
|
||||||
|
_ = wxStaticBoxSizer:add(AccSz, AccTx, wide(5)),
|
||||||
|
KeysSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Additional Account IDs (optional)")}]),
|
||||||
|
KeysTx = wxTextCtrl:new(Frame, ?wxID_ANY, [{style, ?wxTE_MULTILINE}, {value, keys(Keys)}]),
|
||||||
|
_ = wxStaticBoxSizer:add(KeysSz, KeysTx, wide(5)),
|
||||||
|
StatSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Max System Committment (optional)")}]),
|
||||||
|
AProcsS = integer_to_list(AProcs),
|
||||||
|
MProcsS = integer_to_list(MProcs),
|
||||||
|
AMemS = gigs(AMem),
|
||||||
|
MMemS = gigs(MMem),
|
||||||
|
Labels = [{J("HW Cores"), J("Max Cores"), AProcsS, MProcsS}, {J("Memory (GB)"), J("Max Memory"), AMemS, MMemS}],
|
||||||
|
{Grid, [CoresTx, MemoryTx]} = display_box(Frame, Labels),
|
||||||
|
Network = wxRadioBox:new(Frame, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, [J("Mainnet"), J("Testnet")]),
|
||||||
|
ok = wxRadioBox:setSelection(Network, net_num(Net)),
|
||||||
|
|
||||||
|
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
||||||
|
Affirm = wxButton:new(Frame, ?wxID_OK),
|
||||||
|
Cancel = wxButton:new(Frame, ?wxID_CANCEL),
|
||||||
|
_ = wxBoxSizer:add(StatSz, Grid, wide(5)),
|
||||||
|
_ = wxBoxSizer:add(ButtSz, Affirm, wide(5)),
|
||||||
|
_ = wxBoxSizer:add(ButtSz, Cancel, wide(5)),
|
||||||
|
_ = wxBoxSizer:add(MainSz, AccSz, base(5)),
|
||||||
|
_ = wxBoxSizer:add(MainSz, KeysSz, wide(5)),
|
||||||
|
_ = wxBoxSizer:add(MainSz, StatSz, base(5)),
|
||||||
|
_ = wxBoxSizer:add(MainSz, Network, base(5)),
|
||||||
|
_ = wxBoxSizer:add(MainSz, ButtSz, base(5)),
|
||||||
|
ok = wxFrame:setSizer(Frame, MainSz),
|
||||||
|
ok = wxBoxSizer:layout(MainSz),
|
||||||
|
ok = wxFrame:connect(Frame, command_button_clicked),
|
||||||
|
ok = wxFrame:connect(Frame, close_window),
|
||||||
|
ok = wxFrame:setSize(Frame, {500, 500}),
|
||||||
|
ok = wxFrame:center(Frame),
|
||||||
|
true = wxFrame:show(Frame),
|
||||||
|
State =
|
||||||
|
#s{wx = WX, frame = Frame,
|
||||||
|
lang = Lang, j = J,
|
||||||
|
net = Network, acc = AccTx, keys = KeysTx,
|
||||||
|
cores = CoresTx, memory = MemoryTx},
|
||||||
|
{Frame, State}.
|
||||||
|
|
||||||
|
|
||||||
|
base(Padding) -> [{proportion, 0}, {flag, ?wxEXPAND bor ?wxALL}, {border, Padding}].
|
||||||
|
|
||||||
|
wide(Padding) -> [{proportion, 1}, {flag, ?wxEXPAND bor ?wxALL}, {border, Padding}].
|
||||||
|
|
||||||
|
center() -> [{proportion, 0}, {flag, ?wxEXPAND bor ?wxALIGN_CENTER_VERTICAL}].
|
||||||
|
|
||||||
|
gigs(Bytes) ->
|
||||||
|
float_to_list(Bytes / gig(), [{decimals, 2}, compact]).
|
||||||
|
|
||||||
|
gig() -> 1_073_741_824.
|
||||||
|
|
||||||
|
display_box(Parent, Labels) ->
|
||||||
|
Grid = wxFlexGridSizer:new(2, 4, 4),
|
||||||
|
ok = wxFlexGridSizer:setFlexibleDirection(Grid, ?wxHORIZONTAL),
|
||||||
|
ok = wxFlexGridSizer:addGrowableCol(Grid, 1),
|
||||||
|
Make =
|
||||||
|
fun({SO, SI, VS, VM}) ->
|
||||||
|
LO = [SO, ":"],
|
||||||
|
LI = [SI, ":"],
|
||||||
|
T_LO = wxStaticText:new(Parent, ?wxID_ANY, LO),
|
||||||
|
T_CO = wxStaticText:new(Parent, ?wxID_ANY, VS, [{style, ?wxALIGN_LEFT}]),
|
||||||
|
T_LI = wxStaticText:new(Parent, ?wxID_ANY, LI),
|
||||||
|
T_CI = wxTextCtrl:new(Parent, ?wxID_ANY, [{value, VM}]),
|
||||||
|
_ = wxFlexGridSizer:add(Grid, T_LO, center()),
|
||||||
|
_ = wxFlexGridSizer:add(Grid, T_CO, center()),
|
||||||
|
_ = wxFlexGridSizer:add(Grid, T_LI, center()),
|
||||||
|
_ = wxFlexGridSizer:add(Grid, T_CI, zxw:flags(wide)),
|
||||||
|
T_CI
|
||||||
|
end,
|
||||||
|
Controls = lists:map(Make, Labels),
|
||||||
|
{Grid, Controls}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
handle_call(Unexpected, From, State) ->
|
||||||
|
ok = log(warning, "Unexpected call from ~tp: ~tp~n", [From, Unexpected]),
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
|
||||||
|
handle_cast(to_front, State = #s{frame = Frame}) ->
|
||||||
|
ok = wxFrame:raise(Frame),
|
||||||
|
{noreply, State};
|
||||||
|
handle_cast({trouble, Info}, State) ->
|
||||||
|
ok = handle_troubling(State, Info),
|
||||||
|
{noreply, State};
|
||||||
|
handle_cast(Unexpected, State) ->
|
||||||
|
ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]),
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
|
||||||
|
handle_info(Unexpected, State) ->
|
||||||
|
ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]),
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
|
||||||
|
handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID}, State) ->
|
||||||
|
ok =
|
||||||
|
case ID of
|
||||||
|
?wxID_OK -> done(State);
|
||||||
|
?wxID_CANCEL -> buh_bye(State)
|
||||||
|
end,
|
||||||
|
{noreply, State};
|
||||||
|
handle_event(#wx{event = #wxClose{}}, State) ->
|
||||||
|
ok = buh_bye(State),
|
||||||
|
{noreply, State};
|
||||||
|
handle_event(Event, State) ->
|
||||||
|
ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]),
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
|
||||||
|
handle_troubling(#s{frame = Frame}, Info) ->
|
||||||
|
zxw:show_message(Frame, Info).
|
||||||
|
|
||||||
|
|
||||||
|
code_change(_, State, _) ->
|
||||||
|
{ok, State}.
|
||||||
|
|
||||||
|
|
||||||
|
terminate(Reason, State) ->
|
||||||
|
ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]),
|
||||||
|
wx:destroy().
|
||||||
|
|
||||||
|
buh_bye(#s{frame = Frame}) ->
|
||||||
|
wxWindow:destroy(Frame).
|
||||||
|
|
||||||
|
|
||||||
|
%%% Doers
|
||||||
|
|
||||||
|
done(State = #s{net = Network, acc = AccTx, keys = KeysTx, cores = CoresTx, memory = MemTx}) ->
|
||||||
|
Net =
|
||||||
|
case wxRadioBox:getSelection(Network) of
|
||||||
|
0 -> <<"mainnet">>;
|
||||||
|
1 -> <<"testnet">>;
|
||||||
|
_ -> <<"mainnet">>
|
||||||
|
end,
|
||||||
|
AccID = wxTextCtrl:getValue(AccTx),
|
||||||
|
MOAR_IDs = wxTextCtrl:getValue(KeysTx),
|
||||||
|
CoreS = wxTextCtrl:getValue(CoresTx),
|
||||||
|
GigsS = wxTextCtrl:getValue(MemTx),
|
||||||
|
ok = gmc_con:conf({Net, list_to_binary(AccID), binify_keys(MOAR_IDs), cores(CoreS), bytes(GigsS)}),
|
||||||
|
buh_bye(State).
|
||||||
|
|
||||||
|
cores("") ->
|
||||||
|
none;
|
||||||
|
cores(CoreS) ->
|
||||||
|
try
|
||||||
|
list_to_integer(CoreS)
|
||||||
|
catch
|
||||||
|
_:_ -> none
|
||||||
|
end.
|
||||||
|
|
||||||
|
bytes("") ->
|
||||||
|
none;
|
||||||
|
bytes(GigsS) ->
|
||||||
|
try
|
||||||
|
list_to_integer(GigsS) * gig()
|
||||||
|
catch
|
||||||
|
_:_ ->
|
||||||
|
try
|
||||||
|
trunc(list_to_float(GigsS) * gig())
|
||||||
|
catch
|
||||||
|
_:_ -> none
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
% NOTE: 32 is space, 12288 is full-width space.
|
||||||
|
binify_keys(MOAR) ->
|
||||||
|
[list_to_binary(K) || K <- string:lexemes(MOAR, [$\r, $\n, 32, 12288, $\t, $,, $;])].
|
||||||
|
|
||||||
|
|
||||||
|
acc(none) -> "";
|
||||||
|
acc(AKID) -> AKID.
|
||||||
|
|
||||||
|
|
||||||
|
keys(List) ->
|
||||||
|
unicode:characters_to_list(lists:join("\n", List)).
|
||||||
|
|
||||||
|
|
||||||
|
net_num(<<"mainnet">>) -> 0;
|
||||||
|
net_num(<<"testnet">>) -> 1;
|
||||||
|
net_num(_) -> 0.
|
@ -169,8 +169,8 @@ handle_call(Unexpected, From, State) ->
|
|||||||
|
|
||||||
|
|
||||||
handle_cast(ask_conf, State) ->
|
handle_cast(ask_conf, State) ->
|
||||||
ok = conf(State),
|
NewState = conf(State),
|
||||||
{noreply, State};
|
{noreply, NewState};
|
||||||
handle_cast({set_account, ID}, State) ->
|
handle_cast({set_account, ID}, State) ->
|
||||||
ok = set_account(ID, State),
|
ok = set_account(ID, State),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
@ -379,68 +379,10 @@ explorer_url() ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
conf(State = #s{frame = Frame, j = J}) ->
|
conf(State) ->
|
||||||
Outcome = conf(Frame, J),
|
ok = gmc_con:conf(),
|
||||||
ok = tell("Outcome: ~p", [Outcome]),
|
|
||||||
State.
|
State.
|
||||||
|
|
||||||
conf(Frame, J) ->
|
|
||||||
{Acc, Keys, NetNum} = get_conf(),
|
|
||||||
Label = J("Configure GajuMine"),
|
|
||||||
Dialog = wxDialog:new(Frame, ?wxID_ANY, Label, [{size, {400, 400}}]),
|
|
||||||
Sizer = wxBoxSizer:new(?wxVERTICAL),
|
|
||||||
Network = wxRadioBox:new(Dialog, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, [J("Mainnet"), J("Testnet")]),
|
|
||||||
ok = wxRadioBox:setSelection(Network, NetNum),
|
|
||||||
GMAccSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("GajuMining Account ID")}]),
|
|
||||||
GMAccTx = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}, {value, Acc}]),
|
|
||||||
_ = wxStaticBoxSizer:add(GMAccSz, GMAccTx, zxw:flags(wide)),
|
|
||||||
AccsSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Additional Account IDs (optional)")}]),
|
|
||||||
AccsTx = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_MULTILINE}, {value, Keys}]),
|
|
||||||
_ = wxStaticBoxSizer:add(AccsSz, AccsTx, zxw:flags(wide)),
|
|
||||||
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
|
||||||
Affirm = wxButton:new(Dialog, ?wxID_OK),
|
|
||||||
Cancel = wxButton:new(Dialog, ?wxID_CANCEL),
|
|
||||||
_ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, Network, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, GMAccSz, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, AccsSz, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, ButtSz, zxw:flags(wide)),
|
|
||||||
ok = wxDialog:setSizer(Dialog, Sizer),
|
|
||||||
ok = wxBoxSizer:layout(Sizer),
|
|
||||||
ok = wxFrame:center(Dialog),
|
|
||||||
Outcome =
|
|
||||||
case wxDialog:showModal(Dialog) of
|
|
||||||
?wxID_OK ->
|
|
||||||
Net =
|
|
||||||
case wxRadioBox:getSelection(Network) of
|
|
||||||
0 -> <<"mainnet">>;
|
|
||||||
1 -> <<"testnet">>;
|
|
||||||
_ -> <<"mainnet">>
|
|
||||||
end,
|
|
||||||
AccID = wxTextCtrl:getValue(GMAccTx),
|
|
||||||
MOAR_IDs = wxTextCtrl:getValue(AccsTx),
|
|
||||||
{Net, AccID, MOAR_IDs};
|
|
||||||
?wxID_CANCEL ->
|
|
||||||
cancel
|
|
||||||
end,
|
|
||||||
ok = wxDialog:destroy(Dialog),
|
|
||||||
Outcome.
|
|
||||||
|
|
||||||
get_conf() ->
|
|
||||||
{ID, List, Network} = gmc_con:conf(),
|
|
||||||
{acc(ID), keys(List), net_num(Network)}.
|
|
||||||
|
|
||||||
acc(none) -> "";
|
|
||||||
acc(AKID) -> AKID.
|
|
||||||
|
|
||||||
keys(List) ->
|
|
||||||
unicode:characters_to_list(lists:join("\n", List)).
|
|
||||||
|
|
||||||
net_num(<<"mainnet">>) -> 0;
|
|
||||||
net_num(<<"testnet">>) -> 1;
|
|
||||||
net_num(_) -> 0.
|
|
||||||
|
|
||||||
|
|
||||||
open_browser(Frame, J, URL) ->
|
open_browser(Frame, J, URL) ->
|
||||||
case wx_misc:launchDefaultBrowser(URL) of
|
case wx_misc:launchDefaultBrowser(URL) of
|
||||||
|
@ -1,327 +0,0 @@
|
|||||||
%%% @doc
|
|
||||||
%%% GajuMine Setup GUI
|
|
||||||
%%%
|
|
||||||
%%% In the common case, when a user first runs the program they will not have any
|
|
||||||
%%% accounrts, keys, or mining system setup. The purpose of this program is to provide
|
|
||||||
%%% a first-run guide for them to get set up for mining and explain to the user what is
|
|
||||||
%%% going on.
|
|
||||||
%%%
|
|
||||||
%%% There are two cases to cover:
|
|
||||||
%%% 1. A new miner who doesn't know how anything works and needs to get set up from scratch.
|
|
||||||
%%% 2. A miner who does know a bit about how things work and wants to import a key.
|
|
||||||
%%% @end
|
|
||||||
|
|
||||||
-module(gmc_setup).
|
|
||||||
-vsn("0.2.0").
|
|
||||||
-author("Craig Everett <craigeverett@qpq.swiss>").
|
|
||||||
-copyright("Craig Everett <craigeverett@qpq.swiss>").
|
|
||||||
-license("GPL-3.0-or-later").
|
|
||||||
|
|
||||||
-behavior(wx_object).
|
|
||||||
-include_lib("wx/include/wx.hrl").
|
|
||||||
-export([trouble/1, done/0, done/1]).
|
|
||||||
-export([start_link/1]).
|
|
||||||
-export([init/1, terminate/2, code_change/3,
|
|
||||||
handle_call/3, handle_cast/2, handle_info/2, handle_event/2]).
|
|
||||||
-include("$zx_include/zx_logger.hrl").
|
|
||||||
|
|
||||||
|
|
||||||
-record(w,
|
|
||||||
{name = none :: atom(),
|
|
||||||
id = 0 :: integer(),
|
|
||||||
wx = none :: none | wx:wx_object()}).
|
|
||||||
|
|
||||||
-record(s,
|
|
||||||
{wx = none :: none | wx:wx_object(),
|
|
||||||
frame = none :: none | wx:wx_object(),
|
|
||||||
lang = en :: en | jp,
|
|
||||||
j = none :: none | fun(),
|
|
||||||
buttons = [] :: [#w{}]}).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%% Interface functions
|
|
||||||
|
|
||||||
trouble(Info) ->
|
|
||||||
wx_object:cast(?MODULE, {trouble, Info}).
|
|
||||||
|
|
||||||
|
|
||||||
done() ->
|
|
||||||
wx_object:cast(?MODULE, done).
|
|
||||||
|
|
||||||
|
|
||||||
done(Mnemonic) ->
|
|
||||||
wx_object:cast(?MODULE, {done, Mnemonic}).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%% Startup Functions
|
|
||||||
|
|
||||||
start_link(Prefs) ->
|
|
||||||
wx_object:start_link({local, ?MODULE}, ?MODULE, Prefs, []).
|
|
||||||
|
|
||||||
|
|
||||||
init(Prefs) ->
|
|
||||||
ok = log(info, "GUI starting..."),
|
|
||||||
Lang = maps:get(lang, Prefs, en_US),
|
|
||||||
Trans = gd_jt:read_translations(?MODULE),
|
|
||||||
J = gd_jt:j(Lang, Trans),
|
|
||||||
|
|
||||||
WX = wx:new(),
|
|
||||||
Frame = wxFrame:new(WX, ?wxID_ANY, J("GajuMine Setup")),
|
|
||||||
MainSz = wxBoxSizer:new(?wxVERTICAL),
|
|
||||||
|
|
||||||
ButtonTemplates =
|
|
||||||
[{new_key, J("Create a New Account")},
|
|
||||||
{recover, J("Recover Existing Account")}],
|
|
||||||
|
|
||||||
MakeButton =
|
|
||||||
fun({Name, Label}) ->
|
|
||||||
B = wxButton:new(Frame, ?wxID_ANY, [{label, Label}]),
|
|
||||||
#w{name = Name, id = wxButton:getId(B), wx = B}
|
|
||||||
end,
|
|
||||||
|
|
||||||
Buttons = lists:map(MakeButton, ButtonTemplates),
|
|
||||||
|
|
||||||
Add = fun(#w{wx = Button}) -> wxBoxSizer:add(MainSz, Button, zxw:flags(wide)) end,
|
|
||||||
ok = lists:foreach(Add, Buttons),
|
|
||||||
|
|
||||||
ok = wxFrame:setSizer(Frame, MainSz),
|
|
||||||
ok = wxSizer:layout(MainSz),
|
|
||||||
|
|
||||||
ok = wxFrame:connect(Frame, command_button_clicked),
|
|
||||||
ok = wxFrame:connect(Frame, close_window),
|
|
||||||
ok = wxFrame:setSize(Frame, {300, 300}),
|
|
||||||
ok = wxFrame:center(Frame),
|
|
||||||
true = wxFrame:show(Frame),
|
|
||||||
State =
|
|
||||||
#s{wx = WX, frame = Frame,
|
|
||||||
lang = Lang, j = J,
|
|
||||||
buttons = Buttons},
|
|
||||||
{Frame, State}.
|
|
||||||
|
|
||||||
|
|
||||||
handle_call(Unexpected, From, State) ->
|
|
||||||
ok = log(warning, "Unexpected call from ~tp: ~tp~n", [From, Unexpected]),
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
|
|
||||||
handle_cast({trouble, Info}, State) ->
|
|
||||||
ok = handle_troubling(State, Info),
|
|
||||||
{noreply, State};
|
|
||||||
handle_cast(done, State = #s{frame = Frame}) ->
|
|
||||||
ok = gmc_con:end_setup(),
|
|
||||||
ok = wxWindow:destroy(Frame),
|
|
||||||
{noreply, State};
|
|
||||||
handle_cast({done, Mnemonic}, State) ->
|
|
||||||
ok = done(Mnemonic, State),
|
|
||||||
{noreply, State};
|
|
||||||
handle_cast(Unexpected, State) ->
|
|
||||||
ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]),
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
|
|
||||||
handle_info(Unexpected, State) ->
|
|
||||||
ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]),
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
|
|
||||||
handle_event(#wx{event = #wxCommand{type = command_button_clicked},
|
|
||||||
id = ID},
|
|
||||||
State = #s{buttons = Buttons}) ->
|
|
||||||
ok =
|
|
||||||
case lists:keyfind(ID, #w.id, Buttons) of
|
|
||||||
#w{name = new_key} -> new_key(State);
|
|
||||||
#w{name = recover} -> recover(State)
|
|
||||||
end,
|
|
||||||
{noreply, State};
|
|
||||||
handle_event(#wx{event = #wxClose{}}, State = #s{frame = Frame}) ->
|
|
||||||
ok = gmc_con:stop(),
|
|
||||||
ok = wxWindow:destroy(Frame),
|
|
||||||
{noreply, State};
|
|
||||||
handle_event(Event, State) ->
|
|
||||||
ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]),
|
|
||||||
{noreply, State}.
|
|
||||||
|
|
||||||
|
|
||||||
handle_troubling(#s{frame = Frame}, Info) ->
|
|
||||||
zxw:show_message(Frame, Info).
|
|
||||||
|
|
||||||
|
|
||||||
code_change(_, State, _) ->
|
|
||||||
{ok, State}.
|
|
||||||
|
|
||||||
|
|
||||||
terminate(Reason, State) ->
|
|
||||||
ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]),
|
|
||||||
wx:destroy().
|
|
||||||
|
|
||||||
|
|
||||||
new_key(State = #s{frame = Frame, j = J}) ->
|
|
||||||
case new_key(Frame, J) of
|
|
||||||
{ok, Phrase, Network} ->
|
|
||||||
gmc_con:make_key(Phrase, Network);
|
|
||||||
mismatch ->
|
|
||||||
ok = zxw:show_message(Frame, J("Password entered incorrectly. Try again.")),
|
|
||||||
new_key(State);
|
|
||||||
cancel ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
new_key(Frame, J) ->
|
|
||||||
Label = J("Generate New Account Key"),
|
|
||||||
Dialog = wxDialog:new(Frame, ?wxID_ANY, Label, [{size, {500, 180}}]),
|
|
||||||
Sizer = wxBoxSizer:new(?wxVERTICAL),
|
|
||||||
Network = wxRadioBox:new(Dialog, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, [J("Mainnet"), J("Testnet")]),
|
|
||||||
PassSz1 = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Create Password")}]),
|
|
||||||
PassTx1 = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}]),
|
|
||||||
_ = wxStaticBoxSizer:add(PassSz1, PassTx1, zxw:flags(wide)),
|
|
||||||
PassSz2 = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Confirm Password")}]),
|
|
||||||
PassTx2 = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}]),
|
|
||||||
_ = wxStaticBoxSizer:add(PassSz2, PassTx2, zxw:flags(wide)),
|
|
||||||
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
|
||||||
Affirm = wxButton:new(Dialog, ?wxID_OK),
|
|
||||||
Cancel = wxButton:new(Dialog, ?wxID_CANCEL),
|
|
||||||
_ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, Network, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, PassSz1, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, PassSz2, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, ButtSz, zxw:flags(wide)),
|
|
||||||
ok = wxDialog:setSizer(Dialog, Sizer),
|
|
||||||
ok = wxDialog:setSize(Dialog, {400, 300}),
|
|
||||||
ok = wxBoxSizer:layout(Sizer),
|
|
||||||
ok = wxFrame:center(Dialog),
|
|
||||||
Outcome =
|
|
||||||
case wxDialog:showModal(Dialog) of
|
|
||||||
?wxID_OK ->
|
|
||||||
Net =
|
|
||||||
case wxRadioBox:getSelection(Network) of
|
|
||||||
0 -> mainnet;
|
|
||||||
1 -> testnet;
|
|
||||||
_ -> mainnet
|
|
||||||
end,
|
|
||||||
Pass1 = wxTextCtrl:getValue(PassTx1),
|
|
||||||
Pass2 = wxTextCtrl:getValue(PassTx2),
|
|
||||||
case Pass1 =:= Pass2 of
|
|
||||||
true -> {ok, Pass1, Net};
|
|
||||||
false -> mismatch
|
|
||||||
end;
|
|
||||||
?wxID_CANCEL ->
|
|
||||||
cancel
|
|
||||||
end,
|
|
||||||
ok = wxDialog:destroy(Dialog),
|
|
||||||
Outcome.
|
|
||||||
|
|
||||||
|
|
||||||
recover(State = #s{frame = Frame, j = J}) ->
|
|
||||||
case recover(Frame, J) of
|
|
||||||
{ok, Phrase, Mnemonic, Network} ->
|
|
||||||
gmc_con:load_key(Phrase, Mnemonic, Network);
|
|
||||||
mismatch ->
|
|
||||||
ok = zxw:show_message(Frame, J("Password entered incorrectly. Try again.")),
|
|
||||||
recover(State);
|
|
||||||
cancel ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
recover(Frame, J) ->
|
|
||||||
Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Import Account Key")),
|
|
||||||
Sizer = wxBoxSizer:new(?wxVERTICAL),
|
|
||||||
Network = wxRadioBox:new(Dialog, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, [J("Mainnet"), J("Testnet")]),
|
|
||||||
PassSz1 = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Create Password")}]),
|
|
||||||
PassTx1 = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}]),
|
|
||||||
_ = wxStaticBoxSizer:add(PassSz1, PassTx1, zxw:flags(wide)),
|
|
||||||
PassSz2 = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Confirm Password")}]),
|
|
||||||
PassTx2 = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}]),
|
|
||||||
_ = wxStaticBoxSizer:add(PassSz2, PassTx2, zxw:flags(wide)),
|
|
||||||
MnemSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Recovery Phrase")}]),
|
|
||||||
MnemTx = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_MULTILINE}]),
|
|
||||||
_ = wxStaticBoxSizer:add(MnemSz, MnemTx, zxw:flags(wide)),
|
|
||||||
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
|
||||||
Affirm = wxButton:new(Dialog, ?wxID_OK),
|
|
||||||
Cancel = wxButton:new(Dialog, ?wxID_CANCEL),
|
|
||||||
_ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, Network, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, PassSz1, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, PassSz2, zxw:flags(base)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, MnemSz, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, ButtSz, zxw:flags(base)),
|
|
||||||
ok = wxDialog:setSizer(Dialog, Sizer),
|
|
||||||
ok = wxDialog:setSize(Dialog, {400, 400}),
|
|
||||||
ok = wxBoxSizer:layout(Sizer),
|
|
||||||
ok = wxFrame:center(Dialog),
|
|
||||||
Outcome =
|
|
||||||
case wxDialog:showModal(Dialog) of
|
|
||||||
?wxID_OK ->
|
|
||||||
Pass1 = wxTextCtrl:getValue(PassTx1),
|
|
||||||
Pass2 = wxTextCtrl:getValue(PassTx2),
|
|
||||||
case Pass1 =:= Pass2 of
|
|
||||||
true ->
|
|
||||||
Net =
|
|
||||||
case wxRadioBox:getSelection(Network) of
|
|
||||||
0 -> mainnet;
|
|
||||||
1 -> testnet;
|
|
||||||
_ -> mainnet
|
|
||||||
end,
|
|
||||||
Mnemonic = wxTextCtrl:getValue(MnemTx),
|
|
||||||
{ok, Pass1, Mnemonic, Net};
|
|
||||||
false ->
|
|
||||||
mismatch
|
|
||||||
end;
|
|
||||||
?wxID_CANCEL ->
|
|
||||||
cancel
|
|
||||||
end,
|
|
||||||
ok = wxDialog:destroy(Dialog),
|
|
||||||
Outcome.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
done(Mnemonic, #s{frame = Frame, j = J}) ->
|
|
||||||
Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Mnemonic")),
|
|
||||||
Sizer = wxBoxSizer:new(?wxVERTICAL),
|
|
||||||
MnemSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Recovery Phrase")}]),
|
|
||||||
Options = [{value, Mnemonic}, {style, ?wxTE_MULTILINE bor ?wxTE_READONLY}],
|
|
||||||
MnemTx = wxTextCtrl:new(Dialog, ?wxID_ANY, Options),
|
|
||||||
_ = wxStaticBoxSizer:add(MnemSz, MnemTx, zxw:flags(wide)),
|
|
||||||
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
|
|
||||||
CloseB = wxButton:new(Dialog, ?wxID_CANCEL, [{label, J("Close")}]),
|
|
||||||
CopyB = wxButton:new(Dialog, ?wxID_OK, [{label, J("Copy to Clipboard")}]),
|
|
||||||
_ = wxBoxSizer:add(ButtSz, CloseB, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(ButtSz, CopyB, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, MnemSz, zxw:flags(wide)),
|
|
||||||
_ = wxBoxSizer:add(Sizer, ButtSz, zxw:flags(base)),
|
|
||||||
ok = wxDialog:setSizer(Dialog, Sizer),
|
|
||||||
ok = wxBoxSizer:layout(Sizer),
|
|
||||||
ok = wxFrame:center(Dialog),
|
|
||||||
ok = wxStyledTextCtrl:setFocus(MnemTx),
|
|
||||||
ok =
|
|
||||||
case wxDialog:showModal(Dialog) of
|
|
||||||
?wxID_CANCEL -> ok;
|
|
||||||
?wxID_OK -> copy_to_clipboard(Mnemonic)
|
|
||||||
end,
|
|
||||||
ok = wxDialog:destroy(Dialog),
|
|
||||||
ok = gmc_con:end_setup(),
|
|
||||||
ok = wxWindow:destroy(Frame),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
|
|
||||||
copy_to_clipboard(String) ->
|
|
||||||
CB = wxClipboard:get(),
|
|
||||||
case wxClipboard:open(CB) of
|
|
||||||
true ->
|
|
||||||
Text = wxTextDataObject:new([{text, String}]),
|
|
||||||
case wxClipboard:setData(CB, Text) of
|
|
||||||
true ->
|
|
||||||
R = wxClipboard:flush(CB),
|
|
||||||
log(info, "String copied to system clipboard. Flushed: ~p", [R]);
|
|
||||||
false ->
|
|
||||||
log(info, "Failed to copy to clipboard")
|
|
||||||
end,
|
|
||||||
ok = wxClipboard:close(CB);
|
|
||||||
false ->
|
|
||||||
log(info, "Failed to acquire the clipboard.")
|
|
||||||
end.
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user