This commit is contained in:
2026-05-17 12:47:46 +09:00
parent e7478dd35d
commit 127fba5f8f
2 changed files with 170 additions and 417 deletions
+10
View File
@@ -0,0 +1,10 @@
WIP: Adjust procedure description (for now)
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# ブランチ gajuexpress
# Your branch is up to date with 'origin/gajuexpress'.
#
# コミット予定の変更点:
# modified: src/gd_v_express.erl
#
+159 -416
View File
@@ -1,5 +1,35 @@
%%% @doc %%% @doc
%%% The GajuExpress %%% The GajuExpress
% 0. User opens GajuDesk and selects the key (very top widget)
%
% Sending...
%
% 1. The user inputs the public key/ID of the party the data should be sent to
% 2. The user picks the file or directory to send
% 3. The user decides whether to sign the package or be anonymous
% 4. The user sets the package's TTL
% 5. GajuDesk packs up and compresses the bundle.
% 6. GajuDesk asks GajuExpress for a quote based on size/time
% 7. The price is shown
% 8. The user agrees or aborts
% 9. If the user agrees, a payment window opens and they send a payment to GajuExpress
% 10. GajuDesk polls until the payment is included or the user gives up
% 11. Once GajuExpress verifies the payment, the upload begins
% 12. Progress bar
%
%
% Receiving...
%
% 1. User clicks "check for deliveries"
% 2. GajuExpress issues an ID signature challenge
% 3. GajuDesk asks GajuExpress whether there are any packages waiting for Key
% 4. If yes, then the pending deliveries are shown in the delivery panel
% 5. The user selects + clicks open (or double clicks) a package
% 6. User selects where to unpack it in a file dialog
% 7. GajuDesk downloads the package from GajuExpress
% 8. Progress bar
% 9. File is decrypted and optionally signature verified
% 10. GajuExpress deletes their copy of the file
%%% @end %%% @end
@@ -13,7 +43,7 @@
%-behavior(gd_v). %-behavior(gd_v).
-include_lib("wx/include/wx.hrl"). -include_lib("wx/include/wx.hrl").
-export([to_front/0, to_front/1, trouble/1]). -export([to_front/0, to_front/1, trouble/1]).
-export([show/2]). -export([pending/1, accounts/1]).
-export([start_link/1]). -export([start_link/1]).
-export([init/1, terminate/2, code_change/3, -export([init/1, terminate/2, code_change/3,
handle_call/3, handle_cast/2, handle_info/2, handle_event/2]). handle_call/3, handle_cast/2, handle_info/2, handle_event/2]).
@@ -28,14 +58,18 @@
lang = en :: en | jp, lang = en :: en | jp,
j = none :: none | fun(), j = none :: none | fun(),
prefs = #{} :: map(), prefs = #{} :: map(),
price = none :: none | {non_neg_integer(), wx:wx_object()}, keys = #w{} :: #w{},
size = none :: none | {non_neg_integer(), wx:wx_object()}, accs = [] :: [#wr{}],
total = none :: none | {non_neg_integer(), wx:wx_object()}, check = #w{} :: #w{},
list = #w{} :: #w{},
dl = #w{} :: #w{},
dest = none :: none | wx:wx_object(), dest = none :: none | wx:wx_object(),
picker = none :: none | wx:wx_object(), ttl = none :: none | wx:wx_object(),
file = none :: none | wx:wx_object(), path = none :: none | wx:wx_object(),
sign_yn = none :: none | wx:wx_object(), sign = none :: none | wx:wx_object(),
buttons = [] :: [#w{}]}). size = none :: none | wx:wx_object(),
cost = none :: none | wx:wx_object(),
ul = none :: none | wx:wx_object()}).
-record(mochila, -record(mochila,
{tar = <<>> :: binary(), {tar = <<>> :: binary(),
@@ -64,12 +98,20 @@ trouble(Info) ->
wx_object:cast(?MODULE, {trouble, Info}). wx_object:cast(?MODULE, {trouble, Info}).
-spec show(Win, Manifest) -> ok -spec pending(Manifest) -> ok
when Win :: wx:xw_object(), when Manifest :: [Transfer],
Manifest :: [#wr{}]. Transfer :: {Name :: string(), Size :: pos_integer()}.
pending(Manifest) ->
wx_object:cast(?MODULE, {pending, Manifest}).
-spec accounts(Manifest) -> ok
when Manifest :: [#wr{}].
accounts(Manifest) ->
wx_object:cast(?MODULE, {accounts, Manifest}).
show(Win, Manifest) ->
wx_object:cast(Win, {show, Manifest}).
%%% Startup %%% Startup
@@ -77,38 +119,7 @@ show(Win, Manifest) ->
start_link(Args) -> start_link(Args) ->
wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []).
% Sending... init({Prefs, Selected, Keys}) ->
%
% 0. Sender opens GajuExpress interface
% 1. The user inputs the public key/ID of the party the data should be sent to
% 2. The user picks the file or directory to send
% 3. The user decides whether to sign the package or be anonymous
% 4. The user picks which key to send (and sign with if signing)
% 5. The user sets the package's TTL
% 6. GajuDesk packs up and compresses the bundle.
% 7. GajuDesk asks GajuExpress for a quote based on size/time
% 8. The price is shown
% 9. The user agrees or aborts
% 10. If the user agrees, a payment window opens and they send a payment to GajuExpress
% 11. GajuDesk polls until the payment is included or the user gives up
% 12. Once GajuExpress verifies the payment, the upload begins
% 13. Progress bar
%
%
% Receiving...
%
% 1. Sender opens GajuExpress interface
% 2. GajuExpress issues an ID signature challenge
% 3. GajuDesk asks GajuExpress whether there are any packages waiting for Key
% 4. If yes, then the pending deliveries are shown in the delivery panel
% 5. The user selects + clicks open (or double clicks) a package
% 6. User selects where to unpack it in a file dialog
% 7. GajuDesk downloads the package from GajuExpress
% 8. Progress bar
% 9. File is decrypted and optionally signature verified
% 10. GajuExpress deletes their copy of the file
init({Prefs, KeyManifest}) ->
Lang = maps:get(lang, Prefs, en), Lang = maps:get(lang, Prefs, en),
Trans = gd_jt:read_translations(?MODULE), Trans = gd_jt:read_translations(?MODULE),
J = gd_jt:j(Lang, Trans), J = gd_jt:j(Lang, Trans),
@@ -120,32 +131,58 @@ init({Prefs, KeyManifest}) ->
MainSz = wxBoxSizer:new(?wxVERTICAL), MainSz = wxBoxSizer:new(?wxVERTICAL),
LR_Sz = wxBoxSizer:new(?wxHORIZONTAL), LR_Sz = wxBoxSizer:new(?wxHORIZONTAL),
DeliverySz = wxBoxSizer:new(?wxVERTICAL), KeyP = wxChoice:new(Panel, ?wxID_ANY, [{choices, Keys}]),
DeliveryP = wxListBox:new(Panel, ?wxID_ANY, [{style, ?wxLC_SINGLE_SEL}]), KP = #w{name = key_picker, id = wxChoice:getId(KeyP), wx = KeyP},
ZeroBasedSelected = Selected - 1,
ok = wxChoice:setSelection(KeyP, ZeroBasedSelected),
_ = wxStaticBoxSizer:add(MainSz, KeyP, zxw:flags({base, 5})),
% ok = wxListBox:set(DeliveryP, Names), DownloadSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, J("Downloads")}]),
DownloadBox = wxStaticBoxSizer:getStaticBox(DownloadSz),
CheckB = #w{wx = CheckW} = make_button(DownloadBox, check, J("Check for Downloads")),
DownloadP = wxListBox:new(DownloadBox, ?wxID_ANY, [{style, ?wxLC_SINGLE_SEL}]),
DL_L = #w{name = list, id = wxListBox:getId(DownloadP), wx = DownloadP},
DownloadB = #w{wx = DownloadW} = make_button(DownloadBox, dl, J("Download")),
_ = wxButton:disable(DownloadW),
_ = wxBoxSizer:add(DownloadSz, CheckW, zxw:flags({base, 5})),
_ = wxBoxSizer:add(DownloadSz, DownloadP, zxw:flags({wide, 5})),
_ = wxBoxSizer:add(DownloadSz, DownloadW, zxw:flags({base, 5})),
UploadSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, J("Uploads")}]),
UploadBox = wxStaticBoxSizer:getStaticBox(UploadSz),
DestSz = wxStaticBoxSizer:new(?wxHORIZONTAL, UploadBox, [{label, J("Destination ID")}]),
DestBox = wxStaticBoxSizer:getStaticBox(DestSz),
DestT = wxTextCtrl:new(DestBox, ?wxID_ANY),
_ = wxStaticBoxSizer:add(DestSz, DestT),
TTL_Sz = wxStaticBoxSizer:new(?wxHORIZONTAL, UploadBox, [{label, J("Transfer Expiration (Days)")}]),
TTL_Box = wxStaticBoxSizer:getStaticBox(TTL_Sz),
TTL_T = wxTextCtrl:new(TTL_Box, ?wxID_ANY, [{value, "7"}]),
_ = wxStaticBoxSizer:add(TTL_Sz, TTL_T),
PathSz = wxStaticBoxSizer:new(?wxHORIZONTAL, UploadBox, [{label, J("File or Directory")}]),
PathBox = wxStaticBoxSizer:getStaticBox(PathSz),
PathP = wxFilePickerCtrl:new(PathBox, ?wxID_ANY),
_ = wxStaticBoxSizer:add(PathSz, PathP),
SignSz = wxStaticBoxSizer:new(?wxHORIZONTAL, UploadBox, [{label, J("Transfer Signature")}]),
SignBox = wxStaticBoxSizer:getStaticBox(SignSz),
SignC = wxCheckBox:new(SignBox, ?wxID_ANY, J("Do you want to sign this transfer?")),
_ = wxStaticBoxSizer:add(SignSz, SignC),
SizeSz = wxStaticBoxSizer:new(?wxHORIZONTAL, UploadBox, [{label, J("Transfer Details")}]),
SizeBox = wxStaticBoxSizer:getStaticBox(SizeSz),
SizeT = wxStaticText:new(SizeBox, ?wxID_ANY, J("[No File or Directory Selected]")),
_ = wxStaticBoxSizer:add(SizeSz, SizeT),
CostSz = wxStaticBoxSizer:new(?wxHORIZONTAL, UploadBox, [{label, J("Cost to Transfer")}]),
CostBox = wxStaticBoxSizer:getStaticBox(CostSz),
CostT = wxStaticText:new(CostBox, ?wxID_ANY, "[N/A]"),
_ = wxStaticBoxSizer:add(CostSz, CostT),
UploadB = #w{wx = UploadW} = make_button(UploadBox, ul, J("Upload")),
_ = wxButton:disable(UploadW),
_ = wxStaticBoxSizer:add(UploadSz, UploadW),
SendingSz = wxBoxDizer:new(?wxVERTICAL), _ = wxBoxSizer:add(MainSz, DownloadSz, zxw:flags({wide, 5})),
_ = wxBoxSizer:add(MainSz, UploadSz, zxw:flags({wide, 5})),
KeyNames = [Name || #wr{name = Name} <- KeyManifest], ok = wxPanel:setSizer(Panel, MainSz),
ButtSz = wxBoxSizer:new(?wxHORIZONTAL),
ButtonTemplates =
[{open, J("Open")},
{new, J("New")},
{move, J("Move")},
{import, J("Import")},
{drop, J("Drop")}],
MakeButton = button_maker(Panel, ButtSz),
Buttons = lists:map(MakeButton, ButtonTemplates),
_ = wxSizer:add(MainSz, Picker, zxw:flags(wide)),
_ = wxSizer:add(MainSz, ButtSz, zxw:flags(base)),
ok = wxFrame:setSizer(Panel, MainSz),
ok = wxFrame:setSizer(Frame, TopSz), ok = wxFrame:setSizer(Frame, TopSz),
ok = wxSizer:layout(MainSz), ok = wxSizer:layout(TopSz),
NewPrefs = NewPrefs =
case maps:is_key(geometry, Prefs) of case maps:is_key(geometry, Prefs) of
@@ -165,21 +202,19 @@ init({Prefs, KeyManifest}) ->
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 = wxListBox:connect(Picker, command_listbox_doubleclicked), ok = wxListBox:connect(DownloadP, command_listbox_doubleclicked),
State = #s{wx = Wx, frame = Frame, lang = Lang, j = J, prefs = Prefs, State = #s{wx = Wx, frame = Frame, lang = Lang, j = J, prefs = Prefs,
wallets = Manifest, keys = KeyP, accs = Keys,
picker = Picker, check = CheckB, list = DL_L,
buttons = Buttons}, dl = DownloadB,
dest = DestT, ttl = TTL_T, path = PathP, sign = SignC,
size = SizeT, cost = CostT,
ul = UploadB},
{Frame, State}. {Frame, State}.
make_button(Parent, Name, Label) ->
button_maker(Parent, Sizer) -> B = wxButton:new(Parent, ?wxID_ANY, [{label, Label}]),
fun({Name, Label}) -> #w{name = Name, id = wxButton:getId(B), wx = B}.
B = wxButton:new(Parent, ?wxID_ANY, [{label, Label}]),
_ = wxSizer:add(Sizer, B, zxw:flags({wide, 5})),
#w{name = Name, id = wxButton:getId(B), wx = B}
end.
@@ -189,19 +224,19 @@ handle_call(Unexpected, From, State) ->
ok = log(warning, "Unexpected call from ~tp: ~tp~n", [From, Unexpected]), ok = log(warning, "Unexpected call from ~tp: ~tp~n", [From, Unexpected]),
{noreply, State}. {noreply, State}.
handle_cast({pending, Manifest}, State) ->
NewState = do_pending(Manifest, State),
{noreply, NewState};
handle_cast({accounts, Manifest}, State) ->
NewState = do_accounts(Manifest, State),
{noreply, NewState};
handle_cast(to_front, State = #s{frame = Frame}) -> handle_cast(to_front, State = #s{frame = Frame}) ->
ok = ensure_shown(Frame), ok = ensure_shown(Frame),
ok = wxFrame:raise(Frame), ok = wxFrame:raise(Frame),
{noreply, State}; {noreply, State};
handle_cast(first_run, State) ->
NewState = do_first_run(State),
{noreply, NewState};
handle_cast({trouble, Info}, State) -> handle_cast({trouble, Info}, State) ->
ok = handle_troubling(State, Info), ok = handle_troubling(State, Info),
{noreply, State}; {noreply, State};
handle_cast({show, Manifest}, State) ->
NewState = do_show(Manifest, State),
{noreply, NewState};
handle_cast(Unexpected, State) -> handle_cast(Unexpected, State) ->
ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]), ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]),
{noreply, State}. {noreply, State}.
@@ -212,45 +247,30 @@ handle_info(Unexpected, State) ->
{noreply, State}. {noreply, State}.
handle_event(#wx{event = #wxCommand{type = command_button_clicked}, handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID},
id = ID}, State = #s{check = #w{id = ID}}) ->
State = #s{buttons = Buttons, wiz = none}) -> NewState = do_check(State),
NewState = {noreply, NewState};
case lists:keyfind(ID, #w.id, Buttons) of handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID},
#w{name = open} -> do_open(State); State = #s{dl = #w{id = ID}}) ->
#w{name = new} -> do_new(State); NewState = do_dl(State),
#w{name = import} -> do_import(State); {noreply, NewState};
#w{name = drop} -> do_drop(State); handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID},
#w{name = Name} -> handle_button(Name, State); State = #s{ul = #w{id = ID}}) ->
false -> State NewState = do_ul(State),
end,
{noreply, NewState}; {noreply, NewState};
handle_event(#wx{event = #wxCommand{type = command_listbox_doubleclicked, handle_event(#wx{event = #wxCommand{type = command_listbox_doubleclicked,
commandInt = Selected}}, commandInt = Selected}},
State = #s{wiz = none}) -> State) ->
ok = do_open2(Selected + 1, State), NewState = do_dl(State),
{noreply, State}; {noreply, State};
handle_event(#wx{event = #wxClose{}}, State = #s{wiz = none}) -> handle_event(#wx{event = #wxClose{}}, State) ->
ok = do_close(State), ok = do_close(State),
{noreply, State}; {noreply, State};
handle_event(#wx{event = #wxCommand{type = command_button_clicked},
id = ID},
State = #s{wiz = {_, WizButtons}}) ->
NewState =
case lists:keyfind(ID, #w.id, WizButtons) of
#w{name = noob} -> wiz_noob_assist(State);
#w{name = l33t} -> close_wiz(State);
false -> State
end,
{noreply, NewState};
handle_event(#wx{event = #wxClose{}}, State = #s{wiz = {_, _}}) ->
NewState = close_wiz(State),
{noreply, NewState};
handle_event(Event, State) -> handle_event(Event, State) ->
ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]), ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]),
{noreply, State}. {noreply, State}.
handle_troubling(#s{frame = Frame}, Info) -> handle_troubling(#s{frame = Frame}, Info) ->
zxw:show_message(Frame, Info). zxw:show_message(Frame, Info).
@@ -269,30 +289,35 @@ terminate(Reason, State) ->
%%% doers %%% doers
do_show(Manifest, State = #s{picker = Picker}) -> do_show(Manifest, State = #s{keys = KeyP}) ->
Names = [Name || #wr{name = Name} <- Manifest], Names = [Name || #wr{name = Name} <- Manifest],
ok = wxListBox:set(Picker, Names), ok = wxListBox:set(KeyP, Names),
State#s{wallets = Manifest}. State#s{accs = Manifest}.
do_first_run(State = #s{frame = Frame, wallets = Manifest}) -> do_pending(State, Manifest) ->
Count = length(Manifest), ok = tell(info, "Would do_pending: ~p", [Manifest]),
if State.
Count =:= 0 ->
do_wiz(State);
Count =:= 1 ->
do_open(State);
Count > 1 ->
true = wxFrame:show(Frame),
wxFrame:raise(Frame),
State
end.
close_wiz(State = #s{frame = Frame, wiz = {Wiz, _}}) -> do_accounts(State, Manifest) ->
ok = wxWindow:destroy(Wiz), ok = tell(info, "Would do_pending: ~p", [Manifest]),
true = wxFrame:show(Frame), State.
State#s{wiz = none}.
do_check(State) ->
ok = tell(info, "Would do_check."),
State.
do_dl(State) ->
ok = tell(info, "Would do_dl."),
State.
do_ul(State) ->
ok = tell(info, "Would do_ul."),
State.
do_close(#s{frame = Frame, prefs = Prefs}) -> do_close(#s{frame = Frame, prefs = Prefs}) ->
@@ -310,104 +335,6 @@ do_close(#s{frame = Frame, prefs = Prefs}) ->
ok = wxWindow:destroy(Frame). ok = wxWindow:destroy(Frame).
handle_button(Name, State) ->
ok = tell("Button Click: ~p", [Name]),
State.
do_open(State = #s{wallets = []}) ->
State;
do_open(State = #s{wallets = [#wr{pass = true, path = Path}]}) ->
ok = do_open3(Path, State),
State;
do_open(State = #s{wallets = [#wr{pass = false, path = Path}], frame = Frame}) ->
ok =
case gd_con:open_wallet(Path, none) of
ok ->
do_close(State);
Error ->
ok = ensure_shown(Frame),
trouble(Error)
end,
State;
do_open(State = #s{picker = Picker}) ->
case wxListBox:getSelection(Picker) of
-1 ->
State;
Selected ->
ok = do_open2(Selected + 1, State),
State
end.
do_open2(Selected, State = #s{wallets = Wallets}) ->
case lists:nth(Selected, Wallets) of
#wr{pass = true, path = Path} ->
do_open3(Path, State);
#wr{pass = false, path = Path} ->
ok = gd_con:open_wallet(Path, none),
do_close(State)
end.
do_open3(Path, State = #s{frame = Frame, j = J}) ->
Title = J("Passphrase"),
case zxw_modal_text:show(Frame, Title, [{password, true}]) of
{ok, Phrase} ->
case gd_con:open_wallet(Path, Phrase) of
ok -> do_close(State);
Error -> trouble(Error)
end;
cancel ->
ok
end.
do_wiz(State = #s{wx = WX, lang = Lang, wiz = none}) ->
Trans = gd_jt:read_translations(?MODULE),
J = gd_jt:j(Lang, Trans),
Wiz = wxFrame:new(WX, ?wxID_ANY, J("Initializing Wallet")),
MainSz = wxBoxSizer:new(?wxVERTICAL),
ButtonTemplates =
[{noob, J("I'm new!\nCreate a new account for me.")},
{l33t, J("Open the wallet manager.")}],
MakeButton =
fun({Name, Label}) ->
B = wxButton:new(Wiz, ?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(Wiz, MainSz),
ok = wxSizer:layout(MainSz),
ok = wxFrame:connect(Wiz, command_button_clicked),
ok = wxFrame:connect(Wiz, close_window),
ok = wxFrame:setSize(Wiz, {300, 300}),
ok = wxFrame:center(Wiz),
true = wxFrame:show(Wiz),
State#s{wiz = {Wiz, Buttons}}.
wiz_noob_assist(State = #s{j = J, wiz = {Wiz, _}}) ->
DefaultDir = zx_lib:path(var, "otpr", "gajudesk"),
Name = default_name(),
Path = filename:join(DefaultDir, Name),
case do_new2(Path, J, Wiz) of
ok ->
Label = J("Account 1"),
ok = gd_con:make_key({eddsa, ed25519}, 256, Label, <<>>, none, {sha3, 256}),
ok = do_close(State),
State;
abort ->
State
end.
default_name() -> default_name() ->
{{YY, MM, DD}, {Hr, Mn, Sc}} = calendar:local_time(), {{YY, MM, DD}, {Hr, Mn, Sc}} = calendar:local_time(),
Form = "~4.10.0B-~2.10.0B-~2.10.0B_~2.10.0B-~2.10.0B-~2.10.0B", Form = "~4.10.0B-~2.10.0B-~2.10.0B_~2.10.0B-~2.10.0B-~2.10.0B",
@@ -415,190 +342,6 @@ default_name() ->
unicode:characters_to_list(Name ++ ".gaju"). unicode:characters_to_list(Name ++ ".gaju").
do_new(State = #s{frame = Frame, j = J, prefs = Prefs}) ->
DefaultDir = maps:get(dir, Prefs, zx_lib:path(var, "otpr", "gajudesk")),
Options =
[{message, J("Save Location")},
{defaultDir, DefaultDir},
{defaultFile, default_name()},
{wildCard, "*.gaju"},
{sz, {300, 270}},
{style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}],
Dialog = wxFileDialog:new(Frame, Options),
case wxFileDialog:showModal(Dialog) of
?wxID_OK ->
Dir = wxFileDialog:getDirectory(Dialog),
File = wxFileDialog:getFilename(Dialog),
Path = filename:join(Dir, File),
ok = wxFileDialog:destroy(Dialog),
case do_new2(Path, J, Frame) of
ok ->
NewPrefs = maps:put(dir, Dir, Prefs),
NewState = State#s{prefs = NewPrefs},
ok = do_close(NewState),
NewState;
abort ->
State
end;
?wxID_CANCEL ->
ok = wxFileDialog:destroy(Dialog),
State
end.
do_new2(Path, J, Frame) ->
Dialog = wxDialog:new(Frame, ?wxID_ANY, J("New Wallet"), [{size, {400, 250}}]),
Sizer = wxBoxSizer:new(?wxVERTICAL),
NetworkOptions = [J("Mainnet"), J("Testnet")],
Network = wxRadioBox:new(Dialog, ?wxID_ANY, J("Network"), {0, 0}, {50, 50}, NetworkOptions),
NameSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Name")}]),
NameTx = wxTextCtrl:new(Dialog, ?wxID_ANY),
_ = wxSizer:add(NameSz, NameTx, zxw:flags(wide)),
Label1 = J("Passphrase (optional)"),
PassSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, Label1}]),
PassTx = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}]),
_ = wxSizer:add(PassSz, PassTx, zxw:flags(wide)),
Label2= J("Passphrase Confirmation"),
PassConSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, Label2}]),
PassConTx = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_PASSWORD}]),
_ = wxSizer:add(PassConSz, PassConTx, 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)),
_ = wxSizer:add(Sizer, NameSz, zxw:flags(base)),
_ = wxSizer:add(Sizer, PassSz, zxw:flags(base)),
_ = wxSizer:add(Sizer, PassConSz, zxw:flags(base)),
_ = wxSizer:add(Sizer, ButtSz, zxw:flags(wide)),
ok = wxDialog:setSizer(Dialog, Sizer),
ok = wxDialog:setSize(Dialog, {300, 270}),
ok = wxBoxSizer:layout(Sizer),
ok = wxDialog:center(Dialog),
ok = wxStyledTextCtrl:setFocus(NameTx),
Result =
case wxDialog:showModal(Dialog) of
?wxID_OK ->
Net =
case wxRadioBox:getSelection(Network) of
0 -> mainnet;
1 -> testnet;
_ -> mainnet
end,
Name =
case wxTextCtrl:getValue(NameTx) of
"" -> Path;
N -> N
end,
Pass =
case {wxTextCtrl:getValue(PassTx), wxTextCtrl:getValue(PassConTx)} of
{"", ""} -> none;
{P, P} -> P;
{_, _} -> bad
end,
do_new3(Net, Name, Path, Pass);
?wxID_CANCEL ->
abort
end,
ok = wxDialog:destroy(Dialog),
Result.
do_new3(_, _, _, bad) ->
abort;
do_new3(Net, Name, Path, Pass) ->
gd_con:new_wallet(Net, Name, Path, Pass).
do_import(State = #s{frame = Frame, j = J, prefs = Prefs}) ->
DefaultDir = maps:get(dir, Prefs, zx_lib:path(var, "otpr", "gajudesk")),
Options =
[{message, J("Select Wallet File")},
{defaultDir, DefaultDir},
{wildCard, "*.gaju"},
{style, ?wxFD_OPEN}],
Dialog = wxFileDialog:new(Frame, Options),
case wxFileDialog:showModal(Dialog) of
?wxID_OK ->
Dir = wxFileDialog:getDirectory(Dialog),
File = wxFileDialog:getFilename(Dialog),
ok = wxFileDialog:destroy(Dialog),
case do_import2(Dir, File, J, Frame) of
ok ->
NewPrefs = maps:put(dir, Dir, Prefs),
NewState = State#s{prefs = NewPrefs},
ok = do_close(NewState),
NewState;
abort ->
State
end;
?wxID_CANCEL ->
ok = wxFileDialog:destroy(Dialog),
State
end.
do_import2(_, "", _, _) ->
abort;
do_import2(Dir, File, J, Frame) ->
Path = filename:join(Dir, File),
Title = J("Import Wallet"),
NameL = J("Wallet Name"),
PassL = J("Passphrase (leave blank if none)"),
OK_L = J("OK"),
CancelL = J("Cancel"),
case gd_m_wallet_importer:show(Frame, Title, NameL, PassL, OK_L, CancelL) of
{ok, Name, Pass} -> gd_con:import_wallet(Name, Path, Pass);
cancel -> abort
end.
do_drop(State = #s{picker = Picker}) ->
case wxListBox:getSelection(Picker) of
-1 -> State;
Selected -> do_drop(Selected + 1, State)
end.
do_drop(Selected, State = #s{j = J, frame = Frame, wallets = Wallets}) ->
#wr{name = Name, path = Path} = lists:nth(Selected, Wallets),
Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Drop Wallet")),
Sizer = wxBoxSizer:new(?wxVERTICAL),
MessageM = J("REALLY delete wallet?"),
Message = ["\r\n", MessageM, "\r\n\r\n\"", Name, "\""],
MessageT = wxStaticText:new(Dialog, ?wxID_ANY, Message,
[{style, ?wxALIGN_CENTRE_HORIZONTAL}]),
DeleteM = J("Delete file data?"),
DeleteCheck = wxCheckBox:new(Dialog, ?wxID_ANY, DeleteM),
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)),
_ = wxSizer:add(Sizer, MessageT, zxw:flags(base)),
_ = wxSizer:add(Sizer, DeleteCheck, zxw:flags(base)),
_ = wxSizer:add(Sizer, ButtSz, zxw:flags(wide)),
ok = wxDialog:setSizer(Dialog, Sizer),
ok = wxBoxSizer:layout(Sizer),
ok = wxFrame:setSize(Dialog, {500, 200}),
ok = wxFrame:center(Dialog),
ok =
case wxDialog:showModal(Dialog) of
?wxID_OK ->
Delete = wxCheckBox:getValue(DeleteCheck),
gd_con:drop_wallet(Path, Delete);
?wxID_CANCEL ->
ok
end,
State.
ensure_shown(Frame) -> ensure_shown(Frame) ->
case wxWindow:isShown(Frame) of case wxWindow:isShown(Frame) of
true -> true ->