Skip to content

Commit 4d91b58

Browse files
committed
refactor: Improve Dialog UX
- Add Recovery by email in postJoin dialogs - Add an option to let player in to recover in preJoin - Add customizable body description
1 parent 8198985 commit 4d91b58

49 files changed

Lines changed: 486 additions & 24 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

authme-core/src/main/java/fr/xephi/authme/message/MessageKey.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,21 @@ public enum MessageKey {
242242
/** Login dialog submit button label. */
243243
DIALOG_LOGIN_BUTTON("dialog.login.button"),
244244

245+
/** Login dialog body text shown below the title. */
246+
DIALOG_LOGIN_BODY("dialog.login.body"),
247+
248+
/** Login dialog recovery email field label. */
249+
DIALOG_LOGIN_RECOVERY_EMAIL("dialog.login.recovery_email"),
250+
251+
/** Login dialog forgot-password button label. */
252+
DIALOG_LOGIN_RECOVERY_BUTTON("dialog.login.recovery_button"),
253+
245254
/** Register dialog title. */
246255
DIALOG_REGISTER_TITLE("dialog.register.title"),
247256

257+
/** Register dialog body text shown below the title. */
258+
DIALOG_REGISTER_BODY("dialog.register.body"),
259+
248260
/** Register dialog password field label. */
249261
DIALOG_REGISTER_PASSWORD("dialog.register.password"),
250262

@@ -263,6 +275,9 @@ public enum MessageKey {
263275
/** Two-factor dialog title. */
264276
DIALOG_TWO_FACTOR_TITLE("dialog.two_factor.title"),
265277

278+
/** Two-factor dialog body text shown below the title. */
279+
DIALOG_TWO_FACTOR_BODY("dialog.two_factor.body"),
280+
266281
/** Two-factor dialog code field label. */
267282
DIALOG_TWO_FACTOR_CODE("dialog.two_factor.code"),
268283

authme-core/src/main/java/fr/xephi/authme/platform/DialogWindowSpec.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@
1212
* @param secondaryButtonLabel the optional secondary button label
1313
* @param showSecondaryButton whether a secondary button should be rendered
1414
* @param canCloseWithEscape whether the dialog may be dismissed with escape when the platform supports it
15+
* @param secondaryButtonCommand command template the secondary button should execute in post-join dialogs
16+
* (null for pre-join dialogs where the secondary button is a cancel action)
17+
* @param body optional translated body text shown below the title (null = no body)
1518
*/
1619
public record DialogWindowSpec(String title,
1720
List<DialogInputSpec> inputs,
1821
String primaryButtonLabel,
1922
String secondaryButtonLabel,
2023
boolean showSecondaryButton,
21-
boolean canCloseWithEscape) {
24+
boolean canCloseWithEscape,
25+
String secondaryButtonCommand,
26+
String body) {
2227

2328
public DialogWindowSpec {
2429
Objects.requireNonNull(title, "title");
@@ -27,4 +32,16 @@ public record DialogWindowSpec(String title,
2732
Objects.requireNonNull(secondaryButtonLabel, "secondaryButtonLabel");
2833
inputs = List.copyOf(inputs);
2934
}
35+
36+
/** Convenience constructor without body text (body = null). */
37+
public DialogWindowSpec(String title,
38+
List<DialogInputSpec> inputs,
39+
String primaryButtonLabel,
40+
String secondaryButtonLabel,
41+
boolean showSecondaryButton,
42+
boolean canCloseWithEscape,
43+
String secondaryButtonCommand) {
44+
this(title, inputs, primaryButtonLabel, secondaryButtonLabel,
45+
showSecondaryButton, canCloseWithEscape, secondaryButtonCommand, null);
46+
}
3047
}

authme-core/src/main/java/fr/xephi/authme/service/DialogWindowService.java

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,29 @@ public class DialogWindowService {
3232
}
3333

3434
public DialogWindowSpec createLoginDialog(Player player) {
35-
return createLoginDialogSpec(key -> getPostJoinMessage(player, key), false, false);
35+
boolean showRecovery = commonService.getProperty(RegistrationSettings.DIALOG_SHOW_FORGOT_PASSWORD_BUTTON);
36+
boolean showBody = commonService.getProperty(RegistrationSettings.DIALOG_SHOW_BODY);
37+
Function<MessageKey, String> text = key -> getPostJoinMessage(player, key);
38+
39+
List<DialogInputSpec> inputs = new ArrayList<>();
40+
inputs.add(new DialogInputSpec("password",
41+
text.apply(MessageKey.DIALOG_LOGIN_PASSWORD),
42+
DEFAULT_MAX_INPUT_LENGTH));
43+
if (showRecovery) {
44+
inputs.add(new DialogInputSpec("email",
45+
text.apply(MessageKey.DIALOG_LOGIN_RECOVERY_EMAIL),
46+
DEFAULT_MAX_INPUT_LENGTH));
47+
}
48+
49+
return new DialogWindowSpec(
50+
text.apply(MessageKey.DIALOG_LOGIN_TITLE),
51+
inputs,
52+
text.apply(MessageKey.DIALOG_LOGIN_BUTTON),
53+
showRecovery ? text.apply(MessageKey.DIALOG_LOGIN_RECOVERY_BUTTON) : text.apply(MessageKey.DIALOG_CANCEL_BUTTON),
54+
showRecovery,
55+
false,
56+
showRecovery ? "email recover $(email)" : null,
57+
showBody ? text.apply(MessageKey.DIALOG_LOGIN_BODY) : null);
3658
}
3759

3860
public DialogWindowSpec createPreJoinLoginDialog(String playerName) {
@@ -42,15 +64,20 @@ public DialogWindowSpec createPreJoinLoginDialog(String playerName) {
4264
}
4365

4466
public DialogWindowSpec createTotpDialog(Player player) {
67+
boolean showBody = commonService.getProperty(RegistrationSettings.DIALOG_SHOW_BODY);
68+
Function<MessageKey, String> text = key -> getPostJoinMessage(player, key);
69+
4570
return new DialogWindowSpec(
46-
getPostJoinMessage(player, MessageKey.DIALOG_TWO_FACTOR_TITLE),
71+
text.apply(MessageKey.DIALOG_TWO_FACTOR_TITLE),
4772
List.of(new DialogInputSpec("code",
48-
getPostJoinMessage(player, MessageKey.DIALOG_TWO_FACTOR_CODE),
73+
text.apply(MessageKey.DIALOG_TWO_FACTOR_CODE),
4974
TOTP_CODE_MAX_INPUT_LENGTH)),
50-
getPostJoinMessage(player, MessageKey.DIALOG_TWO_FACTOR_BUTTON),
51-
getPostJoinMessage(player, MessageKey.DIALOG_CANCEL_BUTTON),
75+
text.apply(MessageKey.DIALOG_TWO_FACTOR_BUTTON),
76+
text.apply(MessageKey.DIALOG_CANCEL_BUTTON),
5277
false,
53-
false);
78+
false,
79+
null,
80+
showBody ? text.apply(MessageKey.DIALOG_TWO_FACTOR_BODY) : null);
5481
}
5582

5683
public DialogWindowSpec createRegisterDialog(Player player,
@@ -70,6 +97,7 @@ public DialogWindowSpec createPreJoinRegisterDialog(String playerName,
7097
private DialogWindowSpec createLoginDialogSpec(Function<MessageKey, String> textResolver,
7198
boolean showSecondaryButton,
7299
boolean canCloseWithEscape) {
100+
boolean showBody = commonService.getProperty(RegistrationSettings.DIALOG_SHOW_BODY);
73101
return new DialogWindowSpec(
74102
textResolver.apply(MessageKey.DIALOG_LOGIN_TITLE),
75103
List.of(new DialogInputSpec("password",
@@ -78,15 +106,19 @@ private DialogWindowSpec createLoginDialogSpec(Function<MessageKey, String> text
78106
textResolver.apply(MessageKey.DIALOG_LOGIN_BUTTON),
79107
textResolver.apply(MessageKey.DIALOG_CANCEL_BUTTON),
80108
showSecondaryButton,
81-
canCloseWithEscape);
109+
canCloseWithEscape,
110+
null,
111+
showBody ? textResolver.apply(MessageKey.DIALOG_LOGIN_BODY) : null);
82112
}
83113

84114
private DialogWindowSpec createRegisterDialogSpec(RegistrationType type,
85115
RegisterSecondaryArgument secondArg,
86116
Function<MessageKey, String> textResolver,
87117
boolean showSecondaryButton,
88118
boolean canCloseWithEscape) {
119+
boolean showBody = commonService.getProperty(RegistrationSettings.DIALOG_SHOW_BODY);
89120
List<DialogInputSpec> inputs = new ArrayList<>();
121+
90122
if (type == RegistrationType.EMAIL) {
91123
inputs.add(new DialogInputSpec("email",
92124
textResolver.apply(MessageKey.DIALOG_REGISTER_EMAIL),
@@ -97,15 +129,21 @@ private DialogWindowSpec createRegisterDialogSpec(RegistrationType type,
97129
DEFAULT_MAX_INPUT_LENGTH));
98130
}
99131
} else {
132+
// For EMAIL_MANDATORY: email is placed before password — it is the account identifier
133+
// and mirrors the signup order most players expect (email → then choose a password).
134+
if (secondArg == RegisterSecondaryArgument.EMAIL_MANDATORY) {
135+
inputs.add(new DialogInputSpec("email",
136+
textResolver.apply(MessageKey.DIALOG_REGISTER_EMAIL),
137+
DEFAULT_MAX_INPUT_LENGTH));
138+
}
100139
inputs.add(new DialogInputSpec("password",
101140
textResolver.apply(MessageKey.DIALOG_REGISTER_PASSWORD),
102141
DEFAULT_MAX_INPUT_LENGTH));
103142
if (secondArg == RegisterSecondaryArgument.CONFIRMATION) {
104143
inputs.add(new DialogInputSpec("confirm",
105144
textResolver.apply(MessageKey.DIALOG_REGISTER_CONFIRM_PASSWORD),
106145
DEFAULT_MAX_INPUT_LENGTH));
107-
} else if (secondArg == RegisterSecondaryArgument.EMAIL_MANDATORY
108-
|| secondArg == RegisterSecondaryArgument.EMAIL_OPTIONAL) {
146+
} else if (secondArg == RegisterSecondaryArgument.EMAIL_OPTIONAL) {
109147
inputs.add(new DialogInputSpec("email",
110148
textResolver.apply(MessageKey.DIALOG_REGISTER_EMAIL),
111149
DEFAULT_MAX_INPUT_LENGTH));
@@ -118,7 +156,9 @@ private DialogWindowSpec createRegisterDialogSpec(RegistrationType type,
118156
textResolver.apply(MessageKey.DIALOG_REGISTER_BUTTON),
119157
textResolver.apply(MessageKey.DIALOG_CANCEL_BUTTON),
120158
showSecondaryButton,
121-
canCloseWithEscape);
159+
canCloseWithEscape,
160+
null,
161+
showBody ? textResolver.apply(MessageKey.DIALOG_REGISTER_BODY) : null);
122162
}
123163

124164
private String getPostJoinMessage(Player player, MessageKey key) {

authme-core/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ public final class RegistrationSettings implements SettingsHolder {
140140
public static final Property<Boolean> PRE_JOIN_REGISTER_CANCEL_KICKS =
141141
newProperty("settings.registration.preJoinDialog.registerCancelKicks", false);
142142

143+
@Comment({
144+
"Kick players who cancel the Paper/Folia pre-join login dialog.",
145+
"When false, cancelling lets the player join in limbo to use /email recover."})
146+
public static final Property<Boolean> PRE_JOIN_LOGIN_CANCEL_KICKS =
147+
newProperty("settings.registration.preJoinDialog.loginCancelKicks", true);
148+
149+
@Comment({
150+
"Show a 'Forgot Password?' button in the post-join login dialog.",
151+
"When clicked, executes /email recover using the email entered in the recovery field.",
152+
"Requires an email provider to be configured to be useful."})
153+
public static final Property<Boolean> DIALOG_SHOW_FORGOT_PASSWORD_BUTTON =
154+
newProperty("settings.registration.dialog.showForgotPasswordButton", true);
155+
156+
@Comment({
157+
"Show a short description body in login, register, and two-factor dialogs.",
158+
"The body text helps players understand what the dialog is asking them to do."})
159+
public static final Property<Boolean> DIALOG_SHOW_BODY =
160+
newProperty("settings.registration.dialog.showBody", true);
161+
143162

144163
private RegistrationSettings() {
145164
}

authme-core/src/main/resources/messages/messages_bg.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,17 +136,22 @@ verification:
136136
dialog:
137137
login:
138138
title: '&6Вход'
139+
body: '&7Моля, въведете паролата си, за да продължите.'
139140
password: '&fПарола'
141+
recovery_email: '&fИмейл за възстановяване (незадължително)'
142+
recovery_button: '&eЗабравена парола?'
140143
button: '&aВход'
141144
register:
142145
title: '&6Регистрация'
146+
body: '&7Създайте акаунт, за да започнете да играете на сървъра.'
143147
password: '&fПарола'
144148
confirm_password: '&fПотвърди паролата'
145149
email: '&fИмейл'
146150
confirm_email: '&fПотвърди имейла'
147151
button: '&aРегистриране'
148152
two_factor:
149153
title: '&6Двуфакторна автентикация'
154+
body: '&7Отворете приложението за удостоверяване и въведете 6-цифрения код.'
150155
code: '&f2FA код'
151156
button: '&aПотвърди'
152157
button:

authme-core/src/main/resources/messages/messages_br.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,17 +154,22 @@ two_factor:
154154
dialog:
155155
login:
156156
title: '&6Login'
157+
body: '&7Por favor, insira sua senha para continuar.'
157158
password: '&fSenha'
159+
recovery_email: '&fE-mail de recuperação (opcional)'
160+
recovery_button: '&eEsqueceu a senha?'
158161
button: '&aEntrar'
159162
register:
160163
title: '&6Registro'
164+
body: '&7Crie uma conta para começar a jogar neste servidor.'
161165
password: '&fSenha'
162166
confirm_password: '&fConfirmar senha'
163167
email: '&fE-mail'
164168
confirm_email: '&fConfirmar e-mail'
165169
button: '&aRegistrar'
166170
two_factor:
167171
title: '&6Autenticação de dois fatores'
172+
body: '&7Abra seu aplicativo de autenticação e insira o código de 6 dígitos.'
168173
code: '&fCódigo 2FA'
169174
button: '&aVerificar'
170175
button:

authme-core/src/main/resources/messages/messages_cz.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,22 @@ verification:
138138
dialog:
139139
login:
140140
title: '&6Přihlášení'
141+
body: '&7Pro pokračování zadejte své heslo.'
141142
password: '&fHeslo'
143+
recovery_email: '&fObnovovací e-mail (volitelné)'
144+
recovery_button: '&eZapomenuté heslo?'
142145
button: '&aPřihlásit se'
143146
register:
144147
title: '&6Registrace'
148+
body: '&7Vytvořte si účet a začněte hrát na tomto serveru.'
145149
password: '&fHeslo'
146150
confirm_password: '&fPotvrdit heslo'
147151
email: '&fE-mail'
148152
confirm_email: '&fPotvrdit e-mail'
149153
button: '&aRegistrovat'
150154
two_factor:
151155
title: '&6Dvoufaktorové ověření'
156+
body: '&7Otevřete svou autentizační aplikaci a zadejte 6místný kód.'
152157
code: '&fKód 2FA'
153158
button: '&aOvěřit'
154159
button:

authme-core/src/main/resources/messages/messages_de.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,22 @@ verification:
138138
dialog:
139139
login:
140140
title: '&6Anmeldung'
141+
body: '&7Bitte gib dein Passwort ein, um fortzufahren.'
141142
password: '&fPasswort'
143+
recovery_email: '&fWiederherstellungs-E-Mail (optional)'
144+
recovery_button: '&ePasswort vergessen?'
142145
button: '&aAnmelden'
143146
register:
144147
title: '&6Registrierung'
148+
body: '&7Erstelle ein Konto, um auf diesem Server zu spielen.'
145149
password: '&fPasswort'
146150
confirm_password: '&fPasswort bestätigen'
147151
email: '&fE-Mail'
148152
confirm_email: '&fE-Mail bestätigen'
149153
button: '&aRegistrieren'
150154
two_factor:
151155
title: '&6Zwei-Faktor-Authentifizierung'
156+
body: '&7Öffne deine Authentifizierungs-App und gib den 6-stelligen Code ein.'
152157
code: '&f2FA-Code'
153158
button: '&aVerifizieren'
154159
button:

authme-core/src/main/resources/messages/messages_en.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,17 +148,22 @@ two_factor:
148148
dialog:
149149
login:
150150
title: '&6Login'
151+
body: '&7Please enter your password to continue.'
151152
password: '&fPassword'
153+
recovery_email: '&fRecovery Email (optional)'
154+
recovery_button: '&eForgot Password?'
152155
button: '&aLogin'
153156
register:
154157
title: '&6Register'
158+
body: '&7Create an account to start playing on this server.'
155159
password: '&fPassword'
156160
confirm_password: '&fConfirm Password'
157161
email: '&fEmail'
158162
confirm_email: '&fConfirm Email'
159163
button: '&aRegister'
160164
two_factor:
161165
title: '&6Two-Factor Authentication'
166+
body: '&7Open your authenticator app and enter the 6-digit code.'
162167
code: '&f2FA Code'
163168
button: '&aVerify'
164169
button:

authme-core/src/main/resources/messages/messages_eo.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,22 @@ verification:
138138
dialog:
139139
login:
140140
title: '&6Ensaluti'
141+
body: '&7Bonvolu enigi vian pasvorton por daŭrigi.'
141142
password: '&fPasvorto'
143+
recovery_email: '&fRetpoŝto por restarigo (nedeviga)'
144+
recovery_button: '&eForgesita pasvorto?'
142145
button: '&aEnsaluti'
143146
register:
144147
title: '&6Registriĝo'
148+
body: '&7Kreu konton por komenci ludi sur ĉi tiu servilo.'
145149
password: '&fPasvorto'
146150
confirm_password: '&fKonfirmi pasvorton'
147151
email: '&fRetpoŝto'
148152
confirm_email: '&fKonfirmi retpoŝton'
149153
button: '&aRegistriĝi'
150154
two_factor:
151155
title: '&6Du-ŝtupa aŭtentigo'
156+
body: '&7Malfermu vian aŭtentikigan aplikaĵon kaj enigu la 6-cifran kodon.'
152157
code: '&f2FA-kodo'
153158
button: '&aKonfirmi'
154159
button:

0 commit comments

Comments
 (0)