capacitor-extended-dialog 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapacitorExtendedDialog.podspec +17 -0
- package/Package.swift +28 -0
- package/README.md +190 -0
- package/android/build.gradle +59 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/albermonte/extendeddialog/DialogStyleOptions.java +99 -0
- package/android/src/main/java/com/albermonte/extendeddialog/ExtendedDialog.java +734 -0
- package/android/src/main/java/com/albermonte/extendeddialog/ExtendedDialogPlugin.java +207 -0
- package/android/src/main/java/com/albermonte/extendeddialog/FullScreenDialogFragment.java +589 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/android/src/main/res/values/themes.xml +34 -0
- package/dist/docs.json +384 -0
- package/dist/esm/definitions.d.ts +101 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +14 -0
- package/dist/esm/web.js +193 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +207 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +210 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/ExtendedDialogPlugin/ExtendedDialog.swift +497 -0
- package/ios/Sources/ExtendedDialogPlugin/ExtendedDialogPlugin.swift +177 -0
- package/ios/Sources/ExtendedDialogPlugin/FullScreenDialogViewController.swift +506 -0
- package/ios/Tests/ExtendedDialogPluginTests/ExtendedDialogPluginTests.swift +15 -0
- package/package.json +80 -0
|
@@ -0,0 +1,734 @@
|
|
|
1
|
+
package com.albermonte.extendeddialog;
|
|
2
|
+
|
|
3
|
+
import android.app.Activity;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.DialogInterface;
|
|
6
|
+
import android.content.res.ColorStateList;
|
|
7
|
+
import android.text.InputType;
|
|
8
|
+
import android.util.TypedValue;
|
|
9
|
+
import android.view.ContextThemeWrapper;
|
|
10
|
+
import android.view.View;
|
|
11
|
+
import android.view.WindowManager;
|
|
12
|
+
import android.widget.Button;
|
|
13
|
+
import android.widget.LinearLayout;
|
|
14
|
+
import android.widget.TextView;
|
|
15
|
+
import androidx.appcompat.app.AlertDialog;
|
|
16
|
+
import androidx.core.widget.TextViewCompat;
|
|
17
|
+
import androidx.fragment.app.FragmentActivity;
|
|
18
|
+
import com.google.android.material.color.MaterialColors;
|
|
19
|
+
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
20
|
+
import com.google.android.material.textfield.TextInputEditText;
|
|
21
|
+
import com.google.android.material.textfield.TextInputLayout;
|
|
22
|
+
import java.util.ArrayList;
|
|
23
|
+
import java.util.HashSet;
|
|
24
|
+
import java.util.List;
|
|
25
|
+
import java.util.Set;
|
|
26
|
+
import org.json.JSONArray;
|
|
27
|
+
import org.json.JSONException;
|
|
28
|
+
import org.json.JSONObject;
|
|
29
|
+
|
|
30
|
+
public class ExtendedDialog {
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Wraps the given context with a Material3 theme overlay.
|
|
34
|
+
* This ensures MaterialAlertDialogBuilder works regardless of the app's base theme.
|
|
35
|
+
*/
|
|
36
|
+
private Context getThemedContext(Context context) {
|
|
37
|
+
return new ContextThemeWrapper(context, com.google.android.material.R.style.Theme_Material3_DayNight_Dialog);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Applies style options to an AlertDialog after it's shown.
|
|
42
|
+
* When no custom styles are provided, M3 typography is applied by default.
|
|
43
|
+
*/
|
|
44
|
+
private void applyDialogStyles(AlertDialog dialog, DialogStyleOptions styleOptions) {
|
|
45
|
+
// Apply M3 typography defaults first
|
|
46
|
+
applyM3Typography(dialog);
|
|
47
|
+
|
|
48
|
+
if (styleOptions == null || !styleOptions.hasStyles()) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Style positive button
|
|
53
|
+
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
|
54
|
+
if (positiveButton != null) {
|
|
55
|
+
if (styleOptions.getButtonColor() != null) {
|
|
56
|
+
positiveButton.setTextColor(ColorStateList.valueOf(styleOptions.getButtonColor()));
|
|
57
|
+
}
|
|
58
|
+
if (styleOptions.getButtonFontSize() != null) {
|
|
59
|
+
positiveButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getButtonFontSize());
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Style negative button
|
|
64
|
+
Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
|
|
65
|
+
if (negativeButton != null) {
|
|
66
|
+
if (styleOptions.getCancelButtonColor() != null) {
|
|
67
|
+
negativeButton.setTextColor(ColorStateList.valueOf(styleOptions.getCancelButtonColor()));
|
|
68
|
+
}
|
|
69
|
+
if (styleOptions.getButtonFontSize() != null) {
|
|
70
|
+
negativeButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getButtonFontSize());
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Style title text
|
|
75
|
+
// MaterialAlertDialogBuilder uses appcompat's alertTitle, not android's
|
|
76
|
+
TextView titleView = dialog.findViewById(androidx.appcompat.R.id.alertTitle);
|
|
77
|
+
if (titleView != null) {
|
|
78
|
+
if (styleOptions.getTitleColor() != null) {
|
|
79
|
+
titleView.setTextColor(styleOptions.getTitleColor());
|
|
80
|
+
}
|
|
81
|
+
if (styleOptions.getTitleFontSize() != null) {
|
|
82
|
+
titleView.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getTitleFontSize());
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Style message text
|
|
87
|
+
TextView messageView = dialog.findViewById(android.R.id.message);
|
|
88
|
+
if (messageView != null) {
|
|
89
|
+
if (styleOptions.getMessageFontSize() != null) {
|
|
90
|
+
messageView.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getMessageFontSize());
|
|
91
|
+
}
|
|
92
|
+
if (styleOptions.getMessageColor() != null) {
|
|
93
|
+
messageView.setTextColor(styleOptions.getMessageColor());
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Style background
|
|
98
|
+
if (styleOptions.getBackgroundColor() != null && dialog.getWindow() != null) {
|
|
99
|
+
dialog.getWindow().setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(styleOptions.getBackgroundColor()));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Applies Material 3 typography and colors to dialog title, message, and buttons.
|
|
105
|
+
* M3 dialog specs: Title uses onSurface (#1D1B20), Message uses onSurfaceVariant (#49454F),
|
|
106
|
+
* Buttons use colorPrimary (#6750A4 baseline)
|
|
107
|
+
*/
|
|
108
|
+
private void applyM3Typography(AlertDialog dialog) {
|
|
109
|
+
Context ctx = dialog.getContext();
|
|
110
|
+
|
|
111
|
+
// Apply M3 HeadlineSmall to title with onSurface color
|
|
112
|
+
// MaterialAlertDialogBuilder uses appcompat's alertTitle, not android's
|
|
113
|
+
TextView titleView = dialog.findViewById(androidx.appcompat.R.id.alertTitle);
|
|
114
|
+
if (titleView != null) {
|
|
115
|
+
TextViewCompat.setTextAppearance(titleView,
|
|
116
|
+
com.google.android.material.R.style.TextAppearance_Material3_HeadlineSmall);
|
|
117
|
+
// M3 dialog headline color: onSurface (#1D1B20)
|
|
118
|
+
TypedValue onSurface = new TypedValue();
|
|
119
|
+
if (ctx.getTheme().resolveAttribute(com.google.android.material.R.attr.colorOnSurface, onSurface, true)) {
|
|
120
|
+
titleView.setTextColor(onSurface.data);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Apply M3 BodyMedium to message with onSurfaceVariant color
|
|
125
|
+
TextView messageView = dialog.findViewById(android.R.id.message);
|
|
126
|
+
if (messageView != null) {
|
|
127
|
+
TextViewCompat.setTextAppearance(messageView,
|
|
128
|
+
com.google.android.material.R.style.TextAppearance_Material3_BodyMedium);
|
|
129
|
+
// M3 dialog supporting text color: onSurfaceVariant (#49454F)
|
|
130
|
+
TypedValue onSurfaceVariant = new TypedValue();
|
|
131
|
+
if (ctx.getTheme().resolveAttribute(com.google.android.material.R.attr.colorOnSurfaceVariant, onSurfaceVariant, true)) {
|
|
132
|
+
messageView.setTextColor(onSurfaceVariant.data);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Apply M3 colorPrimary to dialog buttons
|
|
137
|
+
// This ensures consistent button colors across all dialogs regardless of app theme
|
|
138
|
+
TypedValue primaryColor = new TypedValue();
|
|
139
|
+
if (ctx.getTheme().resolveAttribute(com.google.android.material.R.attr.colorPrimary, primaryColor, true)) {
|
|
140
|
+
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
|
141
|
+
if (positiveButton != null) {
|
|
142
|
+
positiveButton.setTextColor(ColorStateList.valueOf(primaryColor.data));
|
|
143
|
+
}
|
|
144
|
+
Button negativeButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
|
|
145
|
+
if (negativeButton != null) {
|
|
146
|
+
negativeButton.setTextColor(ColorStateList.valueOf(primaryColor.data));
|
|
147
|
+
}
|
|
148
|
+
Button neutralButton = dialog.getButton(DialogInterface.BUTTON_NEUTRAL);
|
|
149
|
+
if (neutralButton != null) {
|
|
150
|
+
neutralButton.setTextColor(ColorStateList.valueOf(primaryColor.data));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public interface AlertCallback {
|
|
156
|
+
void onDismiss();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public interface ConfirmCallback {
|
|
160
|
+
void onResult(boolean value);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public interface PromptCallback {
|
|
164
|
+
void onResult(String value, boolean cancelled);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public interface SingleSelectCallback {
|
|
168
|
+
void onResult(String value, boolean cancelled);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public interface MultiSelectCallback {
|
|
172
|
+
void onResult(String[] values, boolean cancelled);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public void showAlert(
|
|
176
|
+
Activity activity,
|
|
177
|
+
String title,
|
|
178
|
+
String message,
|
|
179
|
+
String buttonTitle,
|
|
180
|
+
boolean fullscreen,
|
|
181
|
+
DialogStyleOptions styleOptions,
|
|
182
|
+
AlertCallback callback
|
|
183
|
+
) {
|
|
184
|
+
if (fullscreen && activity instanceof FragmentActivity) {
|
|
185
|
+
showFullScreenAlert((FragmentActivity) activity, title, message, buttonTitle, styleOptions, callback);
|
|
186
|
+
} else {
|
|
187
|
+
showBasicAlert(activity, title, message, buttonTitle, styleOptions, callback);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private void showBasicAlert(
|
|
192
|
+
Activity activity,
|
|
193
|
+
String title,
|
|
194
|
+
String message,
|
|
195
|
+
String buttonTitle,
|
|
196
|
+
DialogStyleOptions styleOptions,
|
|
197
|
+
AlertCallback callback
|
|
198
|
+
) {
|
|
199
|
+
activity.runOnUiThread(() -> {
|
|
200
|
+
Context themedContext = getThemedContext(activity);
|
|
201
|
+
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(themedContext,
|
|
202
|
+
R.style.ThemeOverlay_ExtendedDialog_MaterialAlertDialog);
|
|
203
|
+
|
|
204
|
+
if (title != null && !title.isEmpty()) {
|
|
205
|
+
builder.setTitle(title);
|
|
206
|
+
}
|
|
207
|
+
builder.setMessage(message);
|
|
208
|
+
builder.setPositiveButton(buttonTitle != null ? buttonTitle : "OK", (dialog, which) -> callback.onDismiss());
|
|
209
|
+
builder.setOnCancelListener((dialog) -> callback.onDismiss());
|
|
210
|
+
|
|
211
|
+
AlertDialog dialog = builder.create();
|
|
212
|
+
dialog.show();
|
|
213
|
+
applyDialogStyles(dialog, styleOptions);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private void showFullScreenAlert(
|
|
218
|
+
FragmentActivity activity,
|
|
219
|
+
String title,
|
|
220
|
+
String message,
|
|
221
|
+
String buttonTitle,
|
|
222
|
+
DialogStyleOptions styleOptions,
|
|
223
|
+
AlertCallback callback
|
|
224
|
+
) {
|
|
225
|
+
activity.runOnUiThread(() -> {
|
|
226
|
+
FullScreenDialogFragment fragment = FullScreenDialogFragment.newInstance(
|
|
227
|
+
FullScreenDialogFragment.DialogType.ALERT,
|
|
228
|
+
title,
|
|
229
|
+
message,
|
|
230
|
+
buttonTitle != null ? buttonTitle : "OK",
|
|
231
|
+
null,
|
|
232
|
+
null,
|
|
233
|
+
null,
|
|
234
|
+
null,
|
|
235
|
+
false,
|
|
236
|
+
styleOptions
|
|
237
|
+
);
|
|
238
|
+
fragment.setAlertCallback(callback);
|
|
239
|
+
fragment.show(activity.getSupportFragmentManager(), "fullscreen_alert");
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
public void showConfirm(
|
|
244
|
+
Activity activity,
|
|
245
|
+
String title,
|
|
246
|
+
String message,
|
|
247
|
+
String okButtonTitle,
|
|
248
|
+
String cancelButtonTitle,
|
|
249
|
+
boolean fullscreen,
|
|
250
|
+
DialogStyleOptions styleOptions,
|
|
251
|
+
ConfirmCallback callback
|
|
252
|
+
) {
|
|
253
|
+
if (fullscreen && activity instanceof FragmentActivity) {
|
|
254
|
+
showFullScreenConfirm((FragmentActivity) activity, title, message, okButtonTitle, cancelButtonTitle, styleOptions, callback);
|
|
255
|
+
} else {
|
|
256
|
+
showBasicConfirm(activity, title, message, okButtonTitle, cancelButtonTitle, styleOptions, callback);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private void showBasicConfirm(
|
|
261
|
+
Activity activity,
|
|
262
|
+
String title,
|
|
263
|
+
String message,
|
|
264
|
+
String okButtonTitle,
|
|
265
|
+
String cancelButtonTitle,
|
|
266
|
+
DialogStyleOptions styleOptions,
|
|
267
|
+
ConfirmCallback callback
|
|
268
|
+
) {
|
|
269
|
+
activity.runOnUiThread(() -> {
|
|
270
|
+
Context themedContext = getThemedContext(activity);
|
|
271
|
+
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(themedContext,
|
|
272
|
+
R.style.ThemeOverlay_ExtendedDialog_MaterialAlertDialog);
|
|
273
|
+
|
|
274
|
+
if (title != null && !title.isEmpty()) {
|
|
275
|
+
builder.setTitle(title);
|
|
276
|
+
}
|
|
277
|
+
builder.setMessage(message);
|
|
278
|
+
builder.setPositiveButton(okButtonTitle != null ? okButtonTitle : "OK", (dialog, which) -> callback.onResult(true));
|
|
279
|
+
builder.setNegativeButton(cancelButtonTitle != null ? cancelButtonTitle : "Cancel", (dialog, which) ->
|
|
280
|
+
callback.onResult(false)
|
|
281
|
+
);
|
|
282
|
+
builder.setOnCancelListener((dialog) -> callback.onResult(false));
|
|
283
|
+
|
|
284
|
+
AlertDialog dialog = builder.create();
|
|
285
|
+
dialog.show();
|
|
286
|
+
applyDialogStyles(dialog, styleOptions);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private void showFullScreenConfirm(
|
|
291
|
+
FragmentActivity activity,
|
|
292
|
+
String title,
|
|
293
|
+
String message,
|
|
294
|
+
String okButtonTitle,
|
|
295
|
+
String cancelButtonTitle,
|
|
296
|
+
DialogStyleOptions styleOptions,
|
|
297
|
+
ConfirmCallback callback
|
|
298
|
+
) {
|
|
299
|
+
activity.runOnUiThread(() -> {
|
|
300
|
+
FullScreenDialogFragment fragment = FullScreenDialogFragment.newInstance(
|
|
301
|
+
FullScreenDialogFragment.DialogType.CONFIRM,
|
|
302
|
+
title,
|
|
303
|
+
message,
|
|
304
|
+
okButtonTitle != null ? okButtonTitle : "OK",
|
|
305
|
+
cancelButtonTitle != null ? cancelButtonTitle : "Cancel",
|
|
306
|
+
null,
|
|
307
|
+
null,
|
|
308
|
+
null,
|
|
309
|
+
false,
|
|
310
|
+
styleOptions
|
|
311
|
+
);
|
|
312
|
+
fragment.setConfirmCallback(callback);
|
|
313
|
+
fragment.show(activity.getSupportFragmentManager(), "fullscreen_confirm");
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
public void showPrompt(
|
|
318
|
+
Activity activity,
|
|
319
|
+
String title,
|
|
320
|
+
String message,
|
|
321
|
+
String okButtonTitle,
|
|
322
|
+
String cancelButtonTitle,
|
|
323
|
+
String inputPlaceholder,
|
|
324
|
+
String inputText,
|
|
325
|
+
boolean fullscreen,
|
|
326
|
+
boolean focusInput,
|
|
327
|
+
DialogStyleOptions styleOptions,
|
|
328
|
+
PromptCallback callback
|
|
329
|
+
) {
|
|
330
|
+
if (fullscreen && activity instanceof FragmentActivity) {
|
|
331
|
+
showFullScreenPrompt(
|
|
332
|
+
(FragmentActivity) activity,
|
|
333
|
+
title,
|
|
334
|
+
message,
|
|
335
|
+
okButtonTitle,
|
|
336
|
+
cancelButtonTitle,
|
|
337
|
+
inputPlaceholder,
|
|
338
|
+
inputText,
|
|
339
|
+
focusInput,
|
|
340
|
+
styleOptions,
|
|
341
|
+
callback
|
|
342
|
+
);
|
|
343
|
+
} else {
|
|
344
|
+
showBasicPrompt(
|
|
345
|
+
activity,
|
|
346
|
+
title,
|
|
347
|
+
message,
|
|
348
|
+
okButtonTitle,
|
|
349
|
+
cancelButtonTitle,
|
|
350
|
+
inputPlaceholder,
|
|
351
|
+
inputText,
|
|
352
|
+
focusInput,
|
|
353
|
+
styleOptions,
|
|
354
|
+
callback
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
private void showBasicPrompt(
|
|
360
|
+
Activity activity,
|
|
361
|
+
String title,
|
|
362
|
+
String message,
|
|
363
|
+
String okButtonTitle,
|
|
364
|
+
String cancelButtonTitle,
|
|
365
|
+
String inputPlaceholder,
|
|
366
|
+
String inputText,
|
|
367
|
+
boolean focusInput,
|
|
368
|
+
DialogStyleOptions styleOptions,
|
|
369
|
+
PromptCallback callback
|
|
370
|
+
) {
|
|
371
|
+
activity.runOnUiThread(() -> {
|
|
372
|
+
Context themedContext = getThemedContext(activity);
|
|
373
|
+
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(themedContext,
|
|
374
|
+
R.style.ThemeOverlay_ExtendedDialog_MaterialAlertDialog);
|
|
375
|
+
|
|
376
|
+
if (title != null && !title.isEmpty()) {
|
|
377
|
+
builder.setTitle(title);
|
|
378
|
+
}
|
|
379
|
+
builder.setMessage(message);
|
|
380
|
+
|
|
381
|
+
// Use Material 3 TextInputLayout with outlined style
|
|
382
|
+
TextInputLayout textInputLayout = new TextInputLayout(themedContext, null,
|
|
383
|
+
com.google.android.material.R.attr.textInputOutlinedStyle);
|
|
384
|
+
textInputLayout.setBoxBackgroundMode(TextInputLayout.BOX_BACKGROUND_OUTLINE);
|
|
385
|
+
|
|
386
|
+
final TextInputEditText input = new TextInputEditText(textInputLayout.getContext());
|
|
387
|
+
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
|
388
|
+
if (inputPlaceholder != null) {
|
|
389
|
+
textInputLayout.setHint(inputPlaceholder);
|
|
390
|
+
}
|
|
391
|
+
if (inputText != null) {
|
|
392
|
+
input.setText(inputText);
|
|
393
|
+
input.setSelection(inputText.length());
|
|
394
|
+
}
|
|
395
|
+
textInputLayout.addView(input);
|
|
396
|
+
|
|
397
|
+
LinearLayout container = new LinearLayout(themedContext);
|
|
398
|
+
container.setOrientation(LinearLayout.VERTICAL);
|
|
399
|
+
int padding = (int) (20 * activity.getResources().getDisplayMetrics().density);
|
|
400
|
+
container.setPadding(padding, padding / 2, padding, 0);
|
|
401
|
+
container.addView(textInputLayout);
|
|
402
|
+
builder.setView(container);
|
|
403
|
+
|
|
404
|
+
builder.setPositiveButton(okButtonTitle != null ? okButtonTitle : "OK", (dialog, which) ->
|
|
405
|
+
callback.onResult(input.getText().toString(), false)
|
|
406
|
+
);
|
|
407
|
+
builder.setNegativeButton(cancelButtonTitle != null ? cancelButtonTitle : "Cancel", (dialog, which) ->
|
|
408
|
+
callback.onResult("", true)
|
|
409
|
+
);
|
|
410
|
+
builder.setOnCancelListener((dialog) -> callback.onResult("", true));
|
|
411
|
+
|
|
412
|
+
AlertDialog dialog = builder.create();
|
|
413
|
+
if (focusInput) {
|
|
414
|
+
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
|
415
|
+
input.requestFocus();
|
|
416
|
+
} else {
|
|
417
|
+
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
|
|
418
|
+
}
|
|
419
|
+
dialog.show();
|
|
420
|
+
applyDialogStyles(dialog, styleOptions);
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private void showFullScreenPrompt(
|
|
425
|
+
FragmentActivity activity,
|
|
426
|
+
String title,
|
|
427
|
+
String message,
|
|
428
|
+
String okButtonTitle,
|
|
429
|
+
String cancelButtonTitle,
|
|
430
|
+
String inputPlaceholder,
|
|
431
|
+
String inputText,
|
|
432
|
+
boolean focusInput,
|
|
433
|
+
DialogStyleOptions styleOptions,
|
|
434
|
+
PromptCallback callback
|
|
435
|
+
) {
|
|
436
|
+
activity.runOnUiThread(() -> {
|
|
437
|
+
FullScreenDialogFragment fragment = FullScreenDialogFragment.newInstance(
|
|
438
|
+
FullScreenDialogFragment.DialogType.PROMPT,
|
|
439
|
+
title,
|
|
440
|
+
message,
|
|
441
|
+
okButtonTitle != null ? okButtonTitle : "OK",
|
|
442
|
+
cancelButtonTitle != null ? cancelButtonTitle : "Cancel",
|
|
443
|
+
inputPlaceholder,
|
|
444
|
+
inputText,
|
|
445
|
+
null,
|
|
446
|
+
focusInput,
|
|
447
|
+
styleOptions
|
|
448
|
+
);
|
|
449
|
+
fragment.setPromptCallback(callback);
|
|
450
|
+
fragment.show(activity.getSupportFragmentManager(), "fullscreen_prompt");
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
public void showSingleSelect(
|
|
455
|
+
Activity activity,
|
|
456
|
+
String title,
|
|
457
|
+
String message,
|
|
458
|
+
JSONArray options,
|
|
459
|
+
String selectedValue,
|
|
460
|
+
String okButtonTitle,
|
|
461
|
+
String cancelButtonTitle,
|
|
462
|
+
boolean fullscreen,
|
|
463
|
+
DialogStyleOptions styleOptions,
|
|
464
|
+
SingleSelectCallback callback
|
|
465
|
+
) {
|
|
466
|
+
if (fullscreen && activity instanceof FragmentActivity) {
|
|
467
|
+
showFullScreenSingleSelect(
|
|
468
|
+
(FragmentActivity) activity,
|
|
469
|
+
title,
|
|
470
|
+
message,
|
|
471
|
+
options,
|
|
472
|
+
selectedValue,
|
|
473
|
+
okButtonTitle,
|
|
474
|
+
cancelButtonTitle,
|
|
475
|
+
styleOptions,
|
|
476
|
+
callback
|
|
477
|
+
);
|
|
478
|
+
} else {
|
|
479
|
+
showBasicSingleSelect(
|
|
480
|
+
activity,
|
|
481
|
+
title,
|
|
482
|
+
message,
|
|
483
|
+
options,
|
|
484
|
+
selectedValue,
|
|
485
|
+
okButtonTitle,
|
|
486
|
+
cancelButtonTitle,
|
|
487
|
+
styleOptions,
|
|
488
|
+
callback
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
private void showBasicSingleSelect(
|
|
494
|
+
Activity activity,
|
|
495
|
+
String title,
|
|
496
|
+
String message,
|
|
497
|
+
JSONArray options,
|
|
498
|
+
String selectedValue,
|
|
499
|
+
String okButtonTitle,
|
|
500
|
+
String cancelButtonTitle,
|
|
501
|
+
DialogStyleOptions styleOptions,
|
|
502
|
+
SingleSelectCallback callback
|
|
503
|
+
) {
|
|
504
|
+
activity.runOnUiThread(() -> {
|
|
505
|
+
try {
|
|
506
|
+
List<String> labels = new ArrayList<>();
|
|
507
|
+
List<String> values = new ArrayList<>();
|
|
508
|
+
int checkedItem = -1;
|
|
509
|
+
|
|
510
|
+
for (int i = 0; i < options.length(); i++) {
|
|
511
|
+
JSONObject option = options.getJSONObject(i);
|
|
512
|
+
String label = option.getString("label");
|
|
513
|
+
String value = option.getString("value");
|
|
514
|
+
labels.add(label);
|
|
515
|
+
values.add(value);
|
|
516
|
+
if (selectedValue != null && selectedValue.equals(value)) {
|
|
517
|
+
checkedItem = i;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
final int[] selectedIndex = { checkedItem };
|
|
522
|
+
|
|
523
|
+
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getThemedContext(activity),
|
|
524
|
+
R.style.ThemeOverlay_ExtendedDialog_MaterialAlertDialog);
|
|
525
|
+
|
|
526
|
+
if (title != null && !title.isEmpty()) {
|
|
527
|
+
builder.setTitle(title);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
builder.setSingleChoiceItems(labels.toArray(new String[0]), checkedItem, (dialog, which) -> {
|
|
531
|
+
selectedIndex[0] = which;
|
|
532
|
+
// M3 guideline: Enable confirming action when a choice is made
|
|
533
|
+
((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
builder.setPositiveButton(okButtonTitle != null ? okButtonTitle : "OK", (dialog, which) -> {
|
|
537
|
+
if (selectedIndex[0] >= 0 && selectedIndex[0] < values.size()) {
|
|
538
|
+
callback.onResult(values.get(selectedIndex[0]), false);
|
|
539
|
+
} else {
|
|
540
|
+
callback.onResult(null, false);
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
builder.setNegativeButton(cancelButtonTitle != null ? cancelButtonTitle : "Cancel", (dialog, which) ->
|
|
544
|
+
callback.onResult(null, true)
|
|
545
|
+
);
|
|
546
|
+
builder.setOnCancelListener((dialog) -> callback.onResult(null, true));
|
|
547
|
+
|
|
548
|
+
AlertDialog dialog = builder.create();
|
|
549
|
+
dialog.show();
|
|
550
|
+
applyDialogStyles(dialog, styleOptions);
|
|
551
|
+
|
|
552
|
+
// M3 guideline: Disable confirming action until a choice is made
|
|
553
|
+
if (checkedItem < 0) {
|
|
554
|
+
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
|
|
555
|
+
}
|
|
556
|
+
} catch (JSONException e) {
|
|
557
|
+
callback.onResult(null, true);
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
private void showFullScreenSingleSelect(
|
|
563
|
+
FragmentActivity activity,
|
|
564
|
+
String title,
|
|
565
|
+
String message,
|
|
566
|
+
JSONArray options,
|
|
567
|
+
String selectedValue,
|
|
568
|
+
String okButtonTitle,
|
|
569
|
+
String cancelButtonTitle,
|
|
570
|
+
DialogStyleOptions styleOptions,
|
|
571
|
+
SingleSelectCallback callback
|
|
572
|
+
) {
|
|
573
|
+
activity.runOnUiThread(() -> {
|
|
574
|
+
FullScreenDialogFragment fragment = FullScreenDialogFragment.newInstance(
|
|
575
|
+
FullScreenDialogFragment.DialogType.SINGLE_SELECT,
|
|
576
|
+
title,
|
|
577
|
+
message,
|
|
578
|
+
okButtonTitle != null ? okButtonTitle : "OK",
|
|
579
|
+
cancelButtonTitle != null ? cancelButtonTitle : "Cancel",
|
|
580
|
+
null,
|
|
581
|
+
selectedValue,
|
|
582
|
+
options.toString(),
|
|
583
|
+
false,
|
|
584
|
+
styleOptions
|
|
585
|
+
);
|
|
586
|
+
fragment.setSingleSelectCallback(callback);
|
|
587
|
+
fragment.show(activity.getSupportFragmentManager(), "fullscreen_single_select");
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
public void showMultiSelect(
|
|
592
|
+
Activity activity,
|
|
593
|
+
String title,
|
|
594
|
+
String message,
|
|
595
|
+
JSONArray options,
|
|
596
|
+
JSONArray selectedValues,
|
|
597
|
+
String okButtonTitle,
|
|
598
|
+
String cancelButtonTitle,
|
|
599
|
+
boolean fullscreen,
|
|
600
|
+
DialogStyleOptions styleOptions,
|
|
601
|
+
MultiSelectCallback callback
|
|
602
|
+
) {
|
|
603
|
+
if (fullscreen && activity instanceof FragmentActivity) {
|
|
604
|
+
showFullScreenMultiSelect(
|
|
605
|
+
(FragmentActivity) activity,
|
|
606
|
+
title,
|
|
607
|
+
message,
|
|
608
|
+
options,
|
|
609
|
+
selectedValues,
|
|
610
|
+
okButtonTitle,
|
|
611
|
+
cancelButtonTitle,
|
|
612
|
+
styleOptions,
|
|
613
|
+
callback
|
|
614
|
+
);
|
|
615
|
+
} else {
|
|
616
|
+
showBasicMultiSelect(
|
|
617
|
+
activity,
|
|
618
|
+
title,
|
|
619
|
+
message,
|
|
620
|
+
options,
|
|
621
|
+
selectedValues,
|
|
622
|
+
okButtonTitle,
|
|
623
|
+
cancelButtonTitle,
|
|
624
|
+
styleOptions,
|
|
625
|
+
callback
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
private void showBasicMultiSelect(
|
|
631
|
+
Activity activity,
|
|
632
|
+
String title,
|
|
633
|
+
String message,
|
|
634
|
+
JSONArray options,
|
|
635
|
+
JSONArray selectedValues,
|
|
636
|
+
String okButtonTitle,
|
|
637
|
+
String cancelButtonTitle,
|
|
638
|
+
DialogStyleOptions styleOptions,
|
|
639
|
+
MultiSelectCallback callback
|
|
640
|
+
) {
|
|
641
|
+
activity.runOnUiThread(() -> {
|
|
642
|
+
try {
|
|
643
|
+
List<String> labels = new ArrayList<>();
|
|
644
|
+
List<String> values = new ArrayList<>();
|
|
645
|
+
Set<String> selectedSet = new HashSet<>();
|
|
646
|
+
|
|
647
|
+
if (selectedValues != null) {
|
|
648
|
+
for (int i = 0; i < selectedValues.length(); i++) {
|
|
649
|
+
selectedSet.add(selectedValues.getString(i));
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
for (int i = 0; i < options.length(); i++) {
|
|
654
|
+
JSONObject option = options.getJSONObject(i);
|
|
655
|
+
labels.add(option.getString("label"));
|
|
656
|
+
values.add(option.getString("value"));
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
boolean[] checkedItems = new boolean[values.size()];
|
|
660
|
+
for (int i = 0; i < values.size(); i++) {
|
|
661
|
+
checkedItems[i] = selectedSet.contains(values.get(i));
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
final Set<String> resultSet = new HashSet<>(selectedSet);
|
|
665
|
+
|
|
666
|
+
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getThemedContext(activity),
|
|
667
|
+
R.style.ThemeOverlay_ExtendedDialog_MaterialAlertDialog);
|
|
668
|
+
|
|
669
|
+
if (title != null && !title.isEmpty()) {
|
|
670
|
+
builder.setTitle(title);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
builder.setMultiChoiceItems(labels.toArray(new String[0]), checkedItems, (dialog, which, isChecked) -> {
|
|
674
|
+
if (isChecked) {
|
|
675
|
+
resultSet.add(values.get(which));
|
|
676
|
+
} else {
|
|
677
|
+
resultSet.remove(values.get(which));
|
|
678
|
+
}
|
|
679
|
+
// M3 guideline: Enable confirming action when a choice is made
|
|
680
|
+
((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(!resultSet.isEmpty());
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
builder.setPositiveButton(okButtonTitle != null ? okButtonTitle : "OK", (dialog, which) ->
|
|
684
|
+
callback.onResult(resultSet.toArray(new String[0]), false)
|
|
685
|
+
);
|
|
686
|
+
builder.setNegativeButton(cancelButtonTitle != null ? cancelButtonTitle : "Cancel", (dialog, which) ->
|
|
687
|
+
callback.onResult(new String[0], true)
|
|
688
|
+
);
|
|
689
|
+
builder.setOnCancelListener((dialog) -> callback.onResult(new String[0], true));
|
|
690
|
+
|
|
691
|
+
AlertDialog dialog = builder.create();
|
|
692
|
+
dialog.show();
|
|
693
|
+
applyDialogStyles(dialog, styleOptions);
|
|
694
|
+
|
|
695
|
+
// M3 guideline: Disable confirming action until a choice is made
|
|
696
|
+
if (resultSet.isEmpty()) {
|
|
697
|
+
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
|
|
698
|
+
}
|
|
699
|
+
} catch (JSONException e) {
|
|
700
|
+
callback.onResult(new String[0], true);
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
private void showFullScreenMultiSelect(
|
|
706
|
+
FragmentActivity activity,
|
|
707
|
+
String title,
|
|
708
|
+
String message,
|
|
709
|
+
JSONArray options,
|
|
710
|
+
JSONArray selectedValues,
|
|
711
|
+
String okButtonTitle,
|
|
712
|
+
String cancelButtonTitle,
|
|
713
|
+
DialogStyleOptions styleOptions,
|
|
714
|
+
MultiSelectCallback callback
|
|
715
|
+
) {
|
|
716
|
+
activity.runOnUiThread(() -> {
|
|
717
|
+
String selectedValuesStr = selectedValues != null ? selectedValues.toString() : null;
|
|
718
|
+
FullScreenDialogFragment fragment = FullScreenDialogFragment.newInstance(
|
|
719
|
+
FullScreenDialogFragment.DialogType.MULTI_SELECT,
|
|
720
|
+
title,
|
|
721
|
+
message,
|
|
722
|
+
okButtonTitle != null ? okButtonTitle : "OK",
|
|
723
|
+
cancelButtonTitle != null ? cancelButtonTitle : "Cancel",
|
|
724
|
+
null,
|
|
725
|
+
selectedValuesStr,
|
|
726
|
+
options.toString(),
|
|
727
|
+
false,
|
|
728
|
+
styleOptions
|
|
729
|
+
);
|
|
730
|
+
fragment.setMultiSelectCallback(callback);
|
|
731
|
+
fragment.show(activity.getSupportFragmentManager(), "fullscreen_multi_select");
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
}
|