Skip to content

Commit 37e8939

Browse files
committed
Added login button to wizard search page
1 parent 2a450a5 commit 37e8939

3 files changed

Lines changed: 151 additions & 5 deletions

File tree

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package name.abuchen.portfolio.ui.util;
2+
3+
import org.eclipse.core.runtime.jobs.Job;
4+
import org.eclipse.jface.dialogs.Dialog;
5+
import org.eclipse.jface.dialogs.IDialogConstants;
6+
import org.eclipse.jface.dialogs.MessageDialog;
7+
import org.eclipse.jface.layout.GridDataFactory;
8+
import org.eclipse.jface.layout.GridLayoutFactory;
9+
import org.eclipse.swt.SWT;
10+
import org.eclipse.swt.events.SelectionListener;
11+
import org.eclipse.swt.widgets.Button;
12+
import org.eclipse.swt.widgets.Composite;
13+
import org.eclipse.swt.widgets.Control;
14+
import org.eclipse.swt.widgets.Display;
15+
import org.eclipse.swt.widgets.Shell;
16+
17+
import name.abuchen.portfolio.oauth.AuthenticationException;
18+
import name.abuchen.portfolio.oauth.OAuthClient;
19+
import name.abuchen.portfolio.online.Factory;
20+
import name.abuchen.portfolio.online.impl.PortfolioPerformanceFeed;
21+
import name.abuchen.portfolio.ui.Messages;
22+
import name.abuchen.portfolio.ui.PortfolioPlugin;
23+
import name.abuchen.portfolio.ui.preferences.PPIDPreferencePage.AccessTokenRunnable;
24+
import name.abuchen.portfolio.ui.util.swt.ActiveShell;
25+
import name.abuchen.portfolio.ui.util.swt.StyledLabel;
26+
27+
public class LoginButton
28+
{
29+
public static class LoginDialog extends Dialog
30+
{
31+
private OAuthClient oauthClient = OAuthClient.INSTANCE;
32+
33+
public LoginDialog(Shell parentShell)
34+
{
35+
super(parentShell);
36+
}
37+
38+
@Override
39+
protected void configureShell(Shell shell)
40+
{
41+
super.configureShell(shell);
42+
shell.setText(Factory.getQuoteFeed(PortfolioPerformanceFeed.class).getName());
43+
}
44+
45+
@Override
46+
protected Control createDialogArea(Composite parent)
47+
{
48+
Composite container = (Composite) super.createDialogArea(parent);
49+
GridLayoutFactory.fillDefaults().numColumns(1).extendedMargins(10, 10, 10, 10).applyTo(container);
50+
51+
var description = new StyledLabel(container, SWT.WRAP);
52+
GridDataFactory.swtDefaults().hint(500, SWT.DEFAULT).applyTo(description);
53+
description.setText(Messages.PrefDescriptionPortfolioPerformanceID);
54+
55+
return container;
56+
}
57+
58+
@Override
59+
protected void createButtonsForButtonBar(Composite parent)
60+
{
61+
createButton(parent, 1000, oauthClient.isAuthenticated() ? Messages.CmdLogout : Messages.CmdLogin, true);
62+
createButton(parent, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, false);
63+
}
64+
65+
@Override
66+
protected void buttonPressed(int buttonId)
67+
{
68+
switch (buttonId)
69+
{
70+
case 1000 -> {
71+
try
72+
{
73+
if (oauthClient.isAuthenticated())
74+
{
75+
run(() -> {
76+
oauthClient.signOut();
77+
return null;
78+
});
79+
}
80+
else
81+
{
82+
oauthClient.signIn(DesktopAPI::browse);
83+
}
84+
close();
85+
}
86+
catch (AuthenticationException e)
87+
{
88+
PortfolioPlugin.log(e);
89+
MessageDialog.openError(Display.getDefault().getActiveShell(), Messages.LabelError,
90+
e.getMessage());
91+
}
92+
}
93+
case IDialogConstants.CLOSE_ID -> close();
94+
default -> super.buttonPressed(buttonId);
95+
}
96+
}
97+
98+
private static <T> void run(AccessTokenRunnable<T> supplier)
99+
{
100+
Job.createSystem("Asynchronously retrieve token", monitor -> { //$NON-NLS-1$
101+
try
102+
{
103+
supplier.get();
104+
}
105+
catch (AuthenticationException e)
106+
{
107+
Display.getDefault().asyncExec(() -> MessageDialog.openError(Display.getDefault().getActiveShell(),
108+
Messages.LabelError, e.getMessage()));
109+
}
110+
}).schedule();
111+
}
112+
}
113+
114+
private LoginButton()
115+
{
116+
}
117+
118+
public static Button create(Composite parent)
119+
{
120+
var oauthClient = OAuthClient.INSTANCE;
121+
122+
var action = new Button(parent, SWT.NONE);
123+
action.setEnabled(!oauthClient.isAuthenticationOngoing());
124+
action.setText(oauthClient.isAuthenticated() ? Messages.CmdLogout : Messages.CmdLogin);
125+
126+
Runnable updateListener = () -> Display.getDefault().asyncExec(() -> {
127+
action.setEnabled(!oauthClient.isAuthenticationOngoing());
128+
action.setText(oauthClient.isAuthenticated() ? Messages.CmdLogout : Messages.CmdLogin);
129+
});
130+
131+
oauthClient.addStatusListener(updateListener);
132+
parent.addDisposeListener(event -> oauthClient.removeStatusListener(updateListener));
133+
134+
action.addSelectionListener(
135+
SelectionListener.widgetSelectedAdapter(event -> new LoginDialog(ActiveShell.get()).open()));
136+
137+
return action;
138+
}
139+
}

name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/wizards/security/SearchSecurityWizardPage.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import name.abuchen.portfolio.ui.Messages;
4040
import name.abuchen.portfolio.ui.PortfolioPlugin;
4141
import name.abuchen.portfolio.ui.util.Colors;
42+
import name.abuchen.portfolio.ui.util.LoginButton;
4243
import name.abuchen.portfolio.ui.util.SimpleAction;
4344
import name.abuchen.portfolio.ui.util.swt.PaginatedTable;
4445
import name.abuchen.portfolio.util.TextUtil;
@@ -196,6 +197,8 @@ else if (data instanceof String type)
196197
contextMenu.setLocation(location);
197198
contextMenu.setVisible(true);
198199
});
200+
201+
LoginButton.create(buttons);
199202
}
200203

201204
private void setSearchResults(List<ResultItem> elements)

name.abuchen.portfolio/src/name/abuchen/portfolio/oauth/OAuthClient.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,13 @@ public void signIn(Consumer<String> browser) throws AuthenticationException
127127
}
128128
catch (IOException e)
129129
{
130+
ongoingAuthentication.completeExceptionally(e);
130131
throw new AuthenticationException(Messages.OAuthFailedToStartCallbackServer, e);
131132
}
132133

134+
// inform on ongoing authentication
135+
informListeners();
136+
133137
@SuppressWarnings("nls")
134138
String authzUrl = config.baseUrl + config.authEndpoint //
135139
+ "?response_type=code" //
@@ -162,7 +166,7 @@ public void signIn(Consumer<String> browser) throws AuthenticationException
162166
ongoingAuthentication.cancel(true);
163167
informListeners();
164168
}
165-
}, 2, TimeUnit.MINUTES);
169+
}, 1, TimeUnit.MINUTES);
166170

167171
}
168172

@@ -172,7 +176,8 @@ private void handleSignInCallback(AuthorizationCode authorizationCode, PKCE pkce
172176

173177
if (!state.equals(authorizationCode.getState()))
174178
{
175-
ongoingAuthentication.completeExceptionally(new AuthenticationException(Messages.OAuthAuthenticationFailedDueToStateMismatch));
179+
ongoingAuthentication.completeExceptionally(
180+
new AuthenticationException(Messages.OAuthAuthenticationFailedDueToStateMismatch));
176181
return;
177182
}
178183

@@ -190,9 +195,8 @@ private void handleSignInCallback(AuthorizationCode authorizationCode, PKCE pkce
190195
}
191196
catch (IOException e)
192197
{
193-
ongoingAuthentication
194-
.completeExceptionally(
195-
new AuthenticationException(Messages.OAuthFailedToRequestAccessToken, e));
198+
ongoingAuthentication.completeExceptionally(
199+
new AuthenticationException(Messages.OAuthFailedToRequestAccessToken, e));
196200
}
197201
}
198202

0 commit comments

Comments
 (0)