capacitor-extended-dialog 0.0.2 → 0.0.4
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/README.md +131 -61
- package/android/src/main/java/com/albermonte/extendeddialog/ExtendedDialog.java +37 -1
- package/android/src/main/java/com/albermonte/extendeddialog/ExtendedDialogPlugin.java +45 -0
- package/android/src/main/java/com/albermonte/extendeddialog/FullScreenDialogFragment.java +12 -23
- package/android/src/main/java/com/albermonte/extendeddialog/SheetBottomDialogFragment.java +430 -0
- package/android/src/main/res/values/themes.xml +14 -0
- package/dist/docs.json +280 -49
- package/dist/esm/definitions.d.ts +169 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +3 -1
- package/dist/esm/web.js +93 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +93 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +93 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/ExtendedDialogPlugin/ExtendedDialog.swift +104 -2
- package/ios/Sources/ExtendedDialogPlugin/ExtendedDialogPlugin.swift +31 -1
- package/ios/Sources/ExtendedDialogPlugin/FullScreenDialogViewController.swift +441 -72
- package/package.json +2 -2
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
package com.albermonte.extendeddialog;
|
|
2
|
+
|
|
3
|
+
import android.content.DialogInterface;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.content.res.ColorStateList;
|
|
6
|
+
import android.graphics.Bitmap;
|
|
7
|
+
import android.graphics.BitmapFactory;
|
|
8
|
+
import android.os.Bundle;
|
|
9
|
+
import android.util.Base64;
|
|
10
|
+
import android.util.TypedValue;
|
|
11
|
+
import android.view.ContextThemeWrapper;
|
|
12
|
+
import android.view.Gravity;
|
|
13
|
+
import android.view.LayoutInflater;
|
|
14
|
+
import android.view.View;
|
|
15
|
+
import android.view.ViewGroup;
|
|
16
|
+
import android.widget.FrameLayout;
|
|
17
|
+
import android.widget.ImageView;
|
|
18
|
+
import android.widget.LinearLayout;
|
|
19
|
+
import android.widget.ScrollView;
|
|
20
|
+
import android.widget.TextView;
|
|
21
|
+
import android.app.Dialog;
|
|
22
|
+
import androidx.annotation.NonNull;
|
|
23
|
+
import androidx.annotation.Nullable;
|
|
24
|
+
import androidx.core.widget.TextViewCompat;
|
|
25
|
+
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
|
26
|
+
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
|
27
|
+
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
|
28
|
+
import com.google.android.material.button.MaterialButton;
|
|
29
|
+
import com.google.android.material.color.MaterialColors;
|
|
30
|
+
import com.google.android.material.shape.MaterialShapeDrawable;
|
|
31
|
+
import com.google.android.material.shape.ShapeAppearanceModel;
|
|
32
|
+
import java.io.InputStream;
|
|
33
|
+
import java.net.URL;
|
|
34
|
+
import java.util.concurrent.Executor;
|
|
35
|
+
import java.util.concurrent.Executors;
|
|
36
|
+
import org.json.JSONArray;
|
|
37
|
+
import org.json.JSONException;
|
|
38
|
+
import org.json.JSONObject;
|
|
39
|
+
|
|
40
|
+
public class SheetBottomDialogFragment extends BottomSheetDialogFragment {
|
|
41
|
+
|
|
42
|
+
private static final String ARG_TITLE = "title";
|
|
43
|
+
private static final String ARG_HEADER_LOGO = "headerLogo";
|
|
44
|
+
private static final String ARG_ROWS = "rows";
|
|
45
|
+
private static final String ARG_CONFIRM_BUTTON = "confirmButton";
|
|
46
|
+
private static final String ARG_CANCEL_BUTTON = "cancelButton";
|
|
47
|
+
private static final String ARG_FULLSCREEN = "fullscreen";
|
|
48
|
+
|
|
49
|
+
private ExtendedDialog.SheetCallback sheetCallback;
|
|
50
|
+
private boolean dismissed = false;
|
|
51
|
+
private Context themedContext;
|
|
52
|
+
|
|
53
|
+
public static SheetBottomDialogFragment newInstance(
|
|
54
|
+
String title,
|
|
55
|
+
String headerLogo,
|
|
56
|
+
String rowsJson,
|
|
57
|
+
String confirmButton,
|
|
58
|
+
String cancelButton,
|
|
59
|
+
boolean fullscreen,
|
|
60
|
+
DialogStyleOptions styleOptions
|
|
61
|
+
) {
|
|
62
|
+
SheetBottomDialogFragment fragment = new SheetBottomDialogFragment();
|
|
63
|
+
Bundle args = new Bundle();
|
|
64
|
+
args.putString(ARG_TITLE, title);
|
|
65
|
+
args.putString(ARG_HEADER_LOGO, headerLogo);
|
|
66
|
+
args.putString(ARG_ROWS, rowsJson);
|
|
67
|
+
args.putString(ARG_CONFIRM_BUTTON, confirmButton);
|
|
68
|
+
args.putString(ARG_CANCEL_BUTTON, cancelButton);
|
|
69
|
+
args.putBoolean(ARG_FULLSCREEN, fullscreen);
|
|
70
|
+
if (styleOptions != null) {
|
|
71
|
+
styleOptions.writeToBundle(args);
|
|
72
|
+
}
|
|
73
|
+
fragment.setArguments(args);
|
|
74
|
+
return fragment;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public void setSheetCallback(ExtendedDialog.SheetCallback callback) {
|
|
78
|
+
this.sheetCallback = callback;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@NonNull
|
|
82
|
+
@Override
|
|
83
|
+
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
|
84
|
+
Context m3Context = getThemedContext();
|
|
85
|
+
return new BottomSheetDialog(m3Context, R.style.ThemeOverlay_ExtendedDialog_BottomSheetDialog);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private Context getThemedContext() {
|
|
89
|
+
if (themedContext == null) {
|
|
90
|
+
themedContext = new ContextThemeWrapper(requireContext(), com.google.android.material.R.style.Theme_Material3_DayNight_Dialog);
|
|
91
|
+
}
|
|
92
|
+
return themedContext;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@Nullable
|
|
96
|
+
@Override
|
|
97
|
+
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
|
98
|
+
Bundle args = getArguments();
|
|
99
|
+
if (args == null) {
|
|
100
|
+
dismiss();
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
String title = args.getString(ARG_TITLE, "");
|
|
105
|
+
String headerLogo = args.getString(ARG_HEADER_LOGO);
|
|
106
|
+
String rowsJson = args.getString(ARG_ROWS);
|
|
107
|
+
String confirmButton = args.getString(ARG_CONFIRM_BUTTON, "Confirm");
|
|
108
|
+
String cancelButton = args.getString(ARG_CANCEL_BUTTON, "Cancel");
|
|
109
|
+
boolean fullscreen = args.getBoolean(ARG_FULLSCREEN, false);
|
|
110
|
+
DialogStyleOptions styleOptions = DialogStyleOptions.readFromBundle(args);
|
|
111
|
+
|
|
112
|
+
Context ctx = getThemedContext();
|
|
113
|
+
float density = getResources().getDisplayMetrics().density;
|
|
114
|
+
|
|
115
|
+
// Root layout
|
|
116
|
+
LinearLayout root = new LinearLayout(ctx);
|
|
117
|
+
root.setOrientation(LinearLayout.VERTICAL);
|
|
118
|
+
|
|
119
|
+
// Apply background color
|
|
120
|
+
if (styleOptions.getBackgroundColor() != null) {
|
|
121
|
+
// Use MaterialShapeDrawable to preserve rounded corners
|
|
122
|
+
ShapeAppearanceModel shapeModel = ShapeAppearanceModel.builder()
|
|
123
|
+
.setTopLeftCornerSize(28 * density)
|
|
124
|
+
.setTopRightCornerSize(28 * density)
|
|
125
|
+
.setBottomLeftCornerSize(0)
|
|
126
|
+
.setBottomRightCornerSize(0)
|
|
127
|
+
.build();
|
|
128
|
+
MaterialShapeDrawable shapeDrawable = new MaterialShapeDrawable(shapeModel);
|
|
129
|
+
shapeDrawable.setFillColor(ColorStateList.valueOf(styleOptions.getBackgroundColor()));
|
|
130
|
+
root.setBackground(shapeDrawable);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Drag handle (only shown in basic/non-fullscreen mode)
|
|
134
|
+
if (!fullscreen) {
|
|
135
|
+
View dragHandle = new View(ctx);
|
|
136
|
+
int handleWidth = (int) (32 * density);
|
|
137
|
+
int handleHeight = (int) (4 * density);
|
|
138
|
+
LinearLayout.LayoutParams handleParams = new LinearLayout.LayoutParams(handleWidth, handleHeight);
|
|
139
|
+
handleParams.gravity = Gravity.CENTER_HORIZONTAL;
|
|
140
|
+
handleParams.topMargin = (int) (16 * density);
|
|
141
|
+
handleParams.bottomMargin = (int) (8 * density);
|
|
142
|
+
dragHandle.setLayoutParams(handleParams);
|
|
143
|
+
int outlineVariantColor = MaterialColors.getColor(ctx, com.google.android.material.R.attr.colorOutlineVariant, 0xFFCAC4D0);
|
|
144
|
+
android.graphics.drawable.GradientDrawable handleDrawable = new android.graphics.drawable.GradientDrawable();
|
|
145
|
+
handleDrawable.setShape(android.graphics.drawable.GradientDrawable.RECTANGLE);
|
|
146
|
+
handleDrawable.setCornerRadius(handleHeight / 2f);
|
|
147
|
+
handleDrawable.setColor(outlineVariantColor);
|
|
148
|
+
dragHandle.setBackground(handleDrawable);
|
|
149
|
+
root.addView(dragHandle);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ScrollView for content
|
|
153
|
+
ScrollView scrollView = new ScrollView(ctx);
|
|
154
|
+
scrollView.setLayoutParams(new LinearLayout.LayoutParams(
|
|
155
|
+
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f));
|
|
156
|
+
|
|
157
|
+
LinearLayout contentLayout = new LinearLayout(ctx);
|
|
158
|
+
contentLayout.setOrientation(LinearLayout.VERTICAL);
|
|
159
|
+
int horizontalPadding = (int) (24 * density);
|
|
160
|
+
int verticalPadding = (int) (16 * density);
|
|
161
|
+
contentLayout.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
|
162
|
+
|
|
163
|
+
// Header logo
|
|
164
|
+
if (headerLogo != null && !headerLogo.isEmpty()) {
|
|
165
|
+
ImageView logoView = new ImageView(ctx);
|
|
166
|
+
int logoSize = fullscreen ? (int) (64 * density) : (int) (48 * density);
|
|
167
|
+
LinearLayout.LayoutParams logoParams = new LinearLayout.LayoutParams(logoSize, logoSize);
|
|
168
|
+
logoParams.gravity = Gravity.CENTER_HORIZONTAL;
|
|
169
|
+
logoParams.bottomMargin = (int) (12 * density);
|
|
170
|
+
logoView.setLayoutParams(logoParams);
|
|
171
|
+
contentLayout.addView(logoView);
|
|
172
|
+
loadImageAsync(logoView, headerLogo);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Title
|
|
176
|
+
if (title != null && !title.isEmpty()) {
|
|
177
|
+
TextView titleView = new TextView(ctx);
|
|
178
|
+
titleView.setText(title);
|
|
179
|
+
TextViewCompat.setTextAppearance(titleView,
|
|
180
|
+
com.google.android.material.R.style.TextAppearance_Material3_HeadlineSmall);
|
|
181
|
+
if (styleOptions.getTitleColor() != null) {
|
|
182
|
+
titleView.setTextColor(styleOptions.getTitleColor());
|
|
183
|
+
} else {
|
|
184
|
+
int onSurfaceColor = MaterialColors.getColor(ctx, android.R.attr.textColorPrimary, 0xFF1D1B20);
|
|
185
|
+
titleView.setTextColor(onSurfaceColor);
|
|
186
|
+
}
|
|
187
|
+
if (styleOptions.getTitleFontSize() != null) {
|
|
188
|
+
titleView.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getTitleFontSize());
|
|
189
|
+
}
|
|
190
|
+
titleView.setGravity(Gravity.CENTER);
|
|
191
|
+
LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(
|
|
192
|
+
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
193
|
+
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
194
|
+
);
|
|
195
|
+
titleParams.bottomMargin = (int) (20 * density);
|
|
196
|
+
titleView.setLayoutParams(titleParams);
|
|
197
|
+
contentLayout.addView(titleView);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Rows
|
|
201
|
+
if (rowsJson != null) {
|
|
202
|
+
try {
|
|
203
|
+
JSONArray rows = new JSONArray(rowsJson);
|
|
204
|
+
for (int i = 0; i < rows.length(); i++) {
|
|
205
|
+
JSONObject row = rows.getJSONObject(i);
|
|
206
|
+
LinearLayout rowLayout = createSheetRow(ctx, row, styleOptions, density, i < rows.length() - 1);
|
|
207
|
+
contentLayout.addView(rowLayout);
|
|
208
|
+
}
|
|
209
|
+
} catch (JSONException e) {
|
|
210
|
+
// Handle error
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
scrollView.addView(contentLayout);
|
|
215
|
+
root.addView(scrollView);
|
|
216
|
+
|
|
217
|
+
// Button container pinned at bottom
|
|
218
|
+
LinearLayout buttonContainer = new LinearLayout(ctx);
|
|
219
|
+
buttonContainer.setOrientation(LinearLayout.VERTICAL);
|
|
220
|
+
buttonContainer.setPadding(horizontalPadding, (int) (12 * density), horizontalPadding, (int) (4 * density));
|
|
221
|
+
|
|
222
|
+
int primaryColor = MaterialColors.getColor(ctx, android.R.attr.colorPrimary, 0xFF6750A4);
|
|
223
|
+
|
|
224
|
+
// M3 Expressive L-size button: 48dp height, 24dp horizontal padding
|
|
225
|
+
int buttonHeight = (int) (48 * density);
|
|
226
|
+
int buttonHorizontalPadding = (int) (24 * density);
|
|
227
|
+
|
|
228
|
+
// Confirm button (filled style with purple background, white text)
|
|
229
|
+
MaterialButton confirmBtn = new MaterialButton(ctx);
|
|
230
|
+
confirmBtn.setText(confirmButton);
|
|
231
|
+
confirmBtn.setOnClickListener(v -> {
|
|
232
|
+
handleConfirm();
|
|
233
|
+
dismiss();
|
|
234
|
+
});
|
|
235
|
+
if (styleOptions.getButtonColor() != null) {
|
|
236
|
+
confirmBtn.setBackgroundTintList(ColorStateList.valueOf(styleOptions.getButtonColor()));
|
|
237
|
+
} else {
|
|
238
|
+
confirmBtn.setBackgroundTintList(ColorStateList.valueOf(primaryColor));
|
|
239
|
+
}
|
|
240
|
+
confirmBtn.setTextColor(ColorStateList.valueOf(0xFFFFFFFF));
|
|
241
|
+
confirmBtn.setCornerRadius((int) (24 * density));
|
|
242
|
+
confirmBtn.setMinHeight(buttonHeight);
|
|
243
|
+
confirmBtn.setPadding(buttonHorizontalPadding, 0, buttonHorizontalPadding, 0);
|
|
244
|
+
if (styleOptions.getButtonFontSize() != null) {
|
|
245
|
+
confirmBtn.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getButtonFontSize());
|
|
246
|
+
}
|
|
247
|
+
LinearLayout.LayoutParams confirmParams = new LinearLayout.LayoutParams(
|
|
248
|
+
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
249
|
+
confirmBtn.setLayoutParams(confirmParams);
|
|
250
|
+
buttonContainer.addView(confirmBtn);
|
|
251
|
+
|
|
252
|
+
// Cancel button
|
|
253
|
+
MaterialButton cancelBtn = new MaterialButton(ctx, null,
|
|
254
|
+
com.google.android.material.R.attr.borderlessButtonStyle);
|
|
255
|
+
cancelBtn.setText(cancelButton);
|
|
256
|
+
cancelBtn.setOnClickListener(v -> {
|
|
257
|
+
handleCancel();
|
|
258
|
+
dismiss();
|
|
259
|
+
});
|
|
260
|
+
if (styleOptions.getCancelButtonColor() != null) {
|
|
261
|
+
cancelBtn.setTextColor(ColorStateList.valueOf(styleOptions.getCancelButtonColor()));
|
|
262
|
+
} else {
|
|
263
|
+
cancelBtn.setTextColor(ColorStateList.valueOf(primaryColor));
|
|
264
|
+
}
|
|
265
|
+
cancelBtn.setMinHeight(buttonHeight);
|
|
266
|
+
cancelBtn.setPadding(buttonHorizontalPadding, 0, buttonHorizontalPadding, 0);
|
|
267
|
+
if (styleOptions.getButtonFontSize() != null) {
|
|
268
|
+
cancelBtn.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getButtonFontSize());
|
|
269
|
+
}
|
|
270
|
+
LinearLayout.LayoutParams cancelParams = new LinearLayout.LayoutParams(
|
|
271
|
+
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
272
|
+
cancelBtn.setLayoutParams(cancelParams);
|
|
273
|
+
buttonContainer.addView(cancelBtn);
|
|
274
|
+
|
|
275
|
+
root.addView(buttonContainer);
|
|
276
|
+
|
|
277
|
+
return root;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
@Override
|
|
281
|
+
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
282
|
+
super.onViewCreated(view, savedInstanceState);
|
|
283
|
+
|
|
284
|
+
Bundle args = getArguments();
|
|
285
|
+
boolean fullscreen = args != null && args.getBoolean(ARG_FULLSCREEN, false);
|
|
286
|
+
|
|
287
|
+
// Get the bottom sheet view from the dialog
|
|
288
|
+
BottomSheetDialog dialog = (BottomSheetDialog) getDialog();
|
|
289
|
+
if (dialog == null) return;
|
|
290
|
+
|
|
291
|
+
dialog.setOnShowListener(dialogInterface -> {
|
|
292
|
+
BottomSheetDialog d = (BottomSheetDialog) dialogInterface;
|
|
293
|
+
FrameLayout bottomSheet = d.findViewById(com.google.android.material.R.id.design_bottom_sheet);
|
|
294
|
+
if (bottomSheet == null) return;
|
|
295
|
+
|
|
296
|
+
BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
|
|
297
|
+
|
|
298
|
+
if (fullscreen) {
|
|
299
|
+
// Make the bottom sheet fill the entire screen
|
|
300
|
+
ViewGroup.LayoutParams layoutParams = bottomSheet.getLayoutParams();
|
|
301
|
+
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
302
|
+
bottomSheet.setLayoutParams(layoutParams);
|
|
303
|
+
behavior.setFitToContents(false);
|
|
304
|
+
behavior.setSkipCollapsed(true);
|
|
305
|
+
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
306
|
+
// Prevent dragging down in fullscreen mode
|
|
307
|
+
behavior.setDraggable(false);
|
|
308
|
+
} else {
|
|
309
|
+
behavior.setFitToContents(true);
|
|
310
|
+
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
311
|
+
behavior.setSkipCollapsed(true);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private LinearLayout createSheetRow(Context context, JSONObject row, DialogStyleOptions styleOptions, float density, boolean showDivider) throws JSONException {
|
|
317
|
+
LinearLayout rowLayout = new LinearLayout(context);
|
|
318
|
+
rowLayout.setOrientation(LinearLayout.HORIZONTAL);
|
|
319
|
+
rowLayout.setGravity(Gravity.CENTER_VERTICAL);
|
|
320
|
+
LinearLayout.LayoutParams rowParams = new LinearLayout.LayoutParams(
|
|
321
|
+
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
322
|
+
rowLayout.setLayoutParams(rowParams);
|
|
323
|
+
rowLayout.setPadding(0, (int) (8 * density), 0, (int) (8 * density));
|
|
324
|
+
|
|
325
|
+
// Row logo
|
|
326
|
+
if (row.has("logo") && !row.getString("logo").isEmpty()) {
|
|
327
|
+
ImageView rowLogoView = new ImageView(context);
|
|
328
|
+
int logoSize = (int) (24 * density);
|
|
329
|
+
LinearLayout.LayoutParams logoParams = new LinearLayout.LayoutParams(logoSize, logoSize);
|
|
330
|
+
logoParams.rightMargin = (int) (12 * density);
|
|
331
|
+
rowLogoView.setLayoutParams(logoParams);
|
|
332
|
+
rowLayout.addView(rowLogoView);
|
|
333
|
+
loadImageAsync(rowLogoView, row.getString("logo"));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Row title
|
|
337
|
+
TextView rowTitle = new TextView(context);
|
|
338
|
+
rowTitle.setText(row.getString("title"));
|
|
339
|
+
TextViewCompat.setTextAppearance(rowTitle,
|
|
340
|
+
com.google.android.material.R.style.TextAppearance_Material3_TitleMedium);
|
|
341
|
+
if (styleOptions.getMessageColor() != null) {
|
|
342
|
+
rowTitle.setTextColor(styleOptions.getMessageColor());
|
|
343
|
+
} else {
|
|
344
|
+
int onSurfaceColor = MaterialColors.getColor(context, android.R.attr.textColorPrimary, 0xFF1D1B20);
|
|
345
|
+
rowTitle.setTextColor(onSurfaceColor);
|
|
346
|
+
}
|
|
347
|
+
if (styleOptions.getMessageFontSize() != null) {
|
|
348
|
+
rowTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getMessageFontSize());
|
|
349
|
+
}
|
|
350
|
+
LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f);
|
|
351
|
+
rowTitle.setLayoutParams(titleParams);
|
|
352
|
+
rowLayout.addView(rowTitle);
|
|
353
|
+
|
|
354
|
+
// Row value
|
|
355
|
+
if (row.has("value") && !row.getString("value").isEmpty()) {
|
|
356
|
+
TextView rowValue = new TextView(context);
|
|
357
|
+
rowValue.setText(row.getString("value"));
|
|
358
|
+
TextViewCompat.setTextAppearance(rowValue,
|
|
359
|
+
com.google.android.material.R.style.TextAppearance_Material3_BodyLarge);
|
|
360
|
+
int onSurfaceVariantColor = MaterialColors.getColor(context, android.R.attr.textColorSecondary, 0xFF49454F);
|
|
361
|
+
rowValue.setTextColor(onSurfaceVariantColor);
|
|
362
|
+
rowValue.setGravity(Gravity.END);
|
|
363
|
+
if (styleOptions.getMessageFontSize() != null) {
|
|
364
|
+
rowValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, styleOptions.getMessageFontSize());
|
|
365
|
+
}
|
|
366
|
+
rowLayout.addView(rowValue);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Wrap in container with optional divider
|
|
370
|
+
LinearLayout container = new LinearLayout(context);
|
|
371
|
+
container.setOrientation(LinearLayout.VERTICAL);
|
|
372
|
+
container.addView(rowLayout);
|
|
373
|
+
|
|
374
|
+
if (showDivider) {
|
|
375
|
+
View divider = new View(context);
|
|
376
|
+
divider.setBackgroundColor(MaterialColors.getColor(context, android.R.attr.listDivider, 0xFFE0E0E0));
|
|
377
|
+
LinearLayout.LayoutParams dividerParams = new LinearLayout.LayoutParams(
|
|
378
|
+
LinearLayout.LayoutParams.MATCH_PARENT, (int) (1 * density));
|
|
379
|
+
divider.setLayoutParams(dividerParams);
|
|
380
|
+
container.addView(divider);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return container;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private void loadImageAsync(ImageView imageView, String imageUrl) {
|
|
387
|
+
Executor executor = Executors.newSingleThreadExecutor();
|
|
388
|
+
executor.execute(() -> {
|
|
389
|
+
try {
|
|
390
|
+
Bitmap bitmap;
|
|
391
|
+
if (imageUrl.startsWith("data:")) {
|
|
392
|
+
String base64Data = imageUrl.substring(imageUrl.indexOf(",") + 1);
|
|
393
|
+
byte[] decodedBytes = Base64.decode(base64Data, Base64.DEFAULT);
|
|
394
|
+
bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
|
|
395
|
+
} else {
|
|
396
|
+
InputStream inputStream = new URL(imageUrl).openStream();
|
|
397
|
+
bitmap = BitmapFactory.decodeStream(inputStream);
|
|
398
|
+
inputStream.close();
|
|
399
|
+
}
|
|
400
|
+
if (bitmap != null) {
|
|
401
|
+
imageView.post(() -> imageView.setImageBitmap(bitmap));
|
|
402
|
+
}
|
|
403
|
+
} catch (Exception e) {
|
|
404
|
+
// Silently fail - image won't be displayed
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private void handleConfirm() {
|
|
410
|
+
if (dismissed) return;
|
|
411
|
+
dismissed = true;
|
|
412
|
+
if (sheetCallback != null) {
|
|
413
|
+
sheetCallback.onResult(true);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
private void handleCancel() {
|
|
418
|
+
if (dismissed) return;
|
|
419
|
+
dismissed = true;
|
|
420
|
+
if (sheetCallback != null) {
|
|
421
|
+
sheetCallback.onResult(false);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
@Override
|
|
426
|
+
public void onCancel(@NonNull DialogInterface dialog) {
|
|
427
|
+
super.onCancel(dialog);
|
|
428
|
+
handleCancel();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
@@ -31,4 +31,18 @@
|
|
|
31
31
|
<style name="MaterialAlertDialog.ExtendedDialog" parent="MaterialAlertDialog.Material3">
|
|
32
32
|
<item name="shapeAppearance">@style/ShapeAppearance.ExtendedDialog.MediumComponent</item>
|
|
33
33
|
</style>
|
|
34
|
+
|
|
35
|
+
<!-- Material 3 Bottom Sheet Dialog Theme -->
|
|
36
|
+
<style name="ThemeOverlay.ExtendedDialog.BottomSheetDialog" parent="ThemeOverlay.Material3.BottomSheetDialog">
|
|
37
|
+
<item name="bottomSheetStyle">@style/Widget.ExtendedDialog.BottomSheet.Modal</item>
|
|
38
|
+
</style>
|
|
39
|
+
|
|
40
|
+
<style name="Widget.ExtendedDialog.BottomSheet.Modal" parent="Widget.Material3.BottomSheet.Modal">
|
|
41
|
+
<item name="shapeAppearanceOverlay">@style/ShapeAppearance.ExtendedDialog.BottomSheet</item>
|
|
42
|
+
</style>
|
|
43
|
+
|
|
44
|
+
<style name="ShapeAppearance.ExtendedDialog.BottomSheet" parent="">
|
|
45
|
+
<item name="cornerSizeBottomLeft">0dp</item>
|
|
46
|
+
<item name="cornerSizeBottomRight">0dp</item>
|
|
47
|
+
</style>
|
|
34
48
|
</resources>
|