frida-float-menu 1.0.0

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.
Files changed (44) hide show
  1. package/README.md +404 -0
  2. package/lib/api.d.ts +50 -0
  3. package/lib/api.js +149 -0
  4. package/lib/component/button.d.ts +11 -0
  5. package/lib/component/button.js +57 -0
  6. package/lib/component/category.d.ts +8 -0
  7. package/lib/component/category.js +37 -0
  8. package/lib/component/checkBox.d.ts +28 -0
  9. package/lib/component/checkBox.js +199 -0
  10. package/lib/component/collapsible.d.ts +19 -0
  11. package/lib/component/collapsible.js +177 -0
  12. package/lib/component/image.d.ts +18 -0
  13. package/lib/component/image.js +87 -0
  14. package/lib/component/input.d.ts +33 -0
  15. package/lib/component/input.js +346 -0
  16. package/lib/component/selector.d.ts +22 -0
  17. package/lib/component/selector.js +95 -0
  18. package/lib/component/slider.d.ts +18 -0
  19. package/lib/component/slider.js +155 -0
  20. package/lib/component/style/style.d.ts +5 -0
  21. package/lib/component/style/style.js +261 -0
  22. package/lib/component/style/theme.d.ts +29 -0
  23. package/lib/component/style/theme.js +23 -0
  24. package/lib/component/switch.d.ts +12 -0
  25. package/lib/component/switch.js +77 -0
  26. package/lib/component/text.d.ts +9 -0
  27. package/lib/component/text.js +36 -0
  28. package/lib/component/ui-components.d.ts +24 -0
  29. package/lib/component/ui-components.js +49 -0
  30. package/lib/component/views/log-view.d.ts +25 -0
  31. package/lib/component/views/log-view.js +231 -0
  32. package/lib/component/views/tabs-view.d.ts +35 -0
  33. package/lib/component/views/tabs-view.js +296 -0
  34. package/lib/event-emitter.d.ts +10 -0
  35. package/lib/event-emitter.js +52 -0
  36. package/lib/float-menu.d.ts +63 -0
  37. package/lib/float-menu.js +568 -0
  38. package/lib/index.d.ts +12 -0
  39. package/lib/index.js +28 -0
  40. package/lib/logger.d.ts +43 -0
  41. package/lib/logger.js +183 -0
  42. package/lib/utils.d.ts +8 -0
  43. package/lib/utils.js +16 -0
  44. package/package.json +36 -0
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Category = void 0;
4
+ const api_1 = require("../api");
5
+ const style_1 = require("./style/style");
6
+ const ui_components_1 = require("./ui-components");
7
+ class Category extends ui_components_1.UIComponent {
8
+ constructor(id, label) {
9
+ super(id);
10
+ this.label = label;
11
+ this.value = label;
12
+ }
13
+ createView(context) {
14
+ const TextView = api_1.API.TextView;
15
+ const String = api_1.API.JString;
16
+ const LinearLayoutParams = api_1.API.LinearLayoutParams;
17
+ const ViewGroupLayoutParams = api_1.API.ViewGroupLayoutParams;
18
+ this.view = TextView.$new(context);
19
+ this.view.setText(String.$new(this.label));
20
+ (0, style_1.applyStyle)(this.view, "category", this.menu.options.theme);
21
+ this.view.setLayoutParams(LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
22
+ }
23
+ updateView() {
24
+ if (!this.view)
25
+ return;
26
+ Java.scheduleOnMainThread(() => {
27
+ const String = api_1.API.JString;
28
+ this.view.setText(String.$new(this.value));
29
+ });
30
+ }
31
+ setLabel(label) {
32
+ this.label = label;
33
+ this.value = label;
34
+ this.updateView();
35
+ }
36
+ }
37
+ exports.Category = Category;
@@ -0,0 +1,28 @@
1
+ import { UIComponent } from "./ui-components";
2
+ export interface CheckBoxOption {
3
+ id: string;
4
+ label: string;
5
+ [key: string]: any;
6
+ }
7
+ export declare class CheckBoxGroup extends UIComponent {
8
+ private optionsMap;
9
+ private changeHandler?;
10
+ private valueChangeHandler?;
11
+ private triggerText;
12
+ private maxDisplayCount;
13
+ constructor(id: string, options: CheckBoxOption[], initialChecked?: string[], _columns?: number);
14
+ setOnChangeHandler(handler: (value: CheckBoxOption[], item?: {
15
+ id: string;
16
+ checked: boolean;
17
+ }) => void): void;
18
+ setOnValueChangeHandler(handler: (value: CheckBoxOption[]) => void): void;
19
+ setMaxDisplayCount(n: number): void;
20
+ protected createView(context: any): void;
21
+ private openMultiSelectDialog;
22
+ protected updateView(): void;
23
+ private buildDisplayText;
24
+ getCheckedValues(): CheckBoxOption[];
25
+ setChecked(id: string, checked: boolean): void;
26
+ setCheckedValues(checkedIds: string[]): void;
27
+ getOptions(): CheckBoxOption[];
28
+ }
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CheckBoxGroup = void 0;
4
+ const api_1 = require("../api");
5
+ const style_1 = require("./style/style");
6
+ const ui_components_1 = require("./ui-components");
7
+ class CheckBoxGroup extends ui_components_1.UIComponent {
8
+ constructor(id, options, initialChecked = [], _columns = 3) {
9
+ super(id);
10
+ this.optionsMap = new Map();
11
+ this.maxDisplayCount = 3;
12
+ for (const opt of options) {
13
+ const checked = initialChecked.includes(opt.id);
14
+ this.optionsMap.set(opt.id, { ...opt, checked });
15
+ }
16
+ this.value = this.getCheckedValues();
17
+ }
18
+ setOnChangeHandler(handler) {
19
+ this.changeHandler = handler;
20
+ }
21
+ setOnValueChangeHandler(handler) {
22
+ this.valueChangeHandler = handler;
23
+ }
24
+ setMaxDisplayCount(n) {
25
+ this.maxDisplayCount = Math.max(1, n);
26
+ this.updateView();
27
+ }
28
+ createView(context) {
29
+ const LinearLayout = api_1.API.LinearLayout;
30
+ const TextView = api_1.API.TextView;
31
+ const String = api_1.API.JString;
32
+ const ViewGroupLayoutParams = api_1.API.ViewGroupLayoutParams;
33
+ const Gravity = api_1.API.Gravity;
34
+ const root = LinearLayout.$new(context);
35
+ root.setOrientation(LinearLayout.VERTICAL.value);
36
+ root.setLayoutParams(ViewGroupLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
37
+ const trigger = TextView.$new(context);
38
+ trigger.setGravity(Gravity.CENTER_VERTICAL.value);
39
+ trigger.setSingleLine(true);
40
+ (0, style_1.applyStyle)(trigger, "inputTrigger", this.menu.options.theme);
41
+ trigger.setText(String.$new(this.buildDisplayText() + " ▾"));
42
+ const ViewOnClickListener = api_1.API.OnClickListener;
43
+ const self = this;
44
+ const clickListener = Java.registerClass({
45
+ name: "com.frida.MultiSelectTriggerClick" +
46
+ Date.now() +
47
+ Math.random().toString(36).slice(2),
48
+ implements: [ViewOnClickListener],
49
+ methods: {
50
+ onClick: function () {
51
+ self.openMultiSelectDialog(context);
52
+ },
53
+ },
54
+ });
55
+ trigger.setOnClickListener(clickListener.$new());
56
+ root.addView(trigger);
57
+ this.view = root;
58
+ this.triggerText = trigger;
59
+ }
60
+ openMultiSelectDialog(context) {
61
+ const AlertDialogBuilder = api_1.API.AlertDialogBuilder;
62
+ const String = api_1.API.JString;
63
+ const opts = Array.from(this.optionsMap.values());
64
+ const labels = opts.map((o) => o.label);
65
+ const checkedArr = opts.map((o) => !!o.checked);
66
+ const csArray = Java.array("java.lang.CharSequence", labels.map((s) => String.$new(s)));
67
+ const boolArray = Java.array("boolean", checkedArr);
68
+ const DialogMultiChoiceListener = api_1.API.DialogMultiChoiceListener;
69
+ const DialogClickListener = api_1.API.DialogClickListener;
70
+ const self = this;
71
+ const multiListener = Java.registerClass({
72
+ name: "com.frida.MultiChoiceListener" +
73
+ Date.now() +
74
+ Math.random().toString(36).slice(2),
75
+ implements: [DialogMultiChoiceListener],
76
+ methods: {
77
+ onClick: function (_dialog, which, isChecked) {
78
+ const opt = opts[which];
79
+ self.optionsMap.set(opt.id, { ...opt, checked: isChecked });
80
+ self.value = self.getCheckedValues();
81
+ self.emit("change", self.value, { id: opt.id, checked: isChecked });
82
+ if (self.changeHandler)
83
+ setImmediate(() => self.changeHandler(self.value, {
84
+ id: opt.id,
85
+ checked: isChecked,
86
+ }));
87
+ },
88
+ },
89
+ });
90
+ const okListener = Java.registerClass({
91
+ name: "com.frida.MultiChoiceOk" +
92
+ Date.now() +
93
+ Math.random().toString(36).slice(2),
94
+ implements: [DialogClickListener],
95
+ methods: {
96
+ onClick: function (dialog, _which) {
97
+ self.value = self.getCheckedValues();
98
+ self.updateView();
99
+ self.emit("valueChanged", self.value);
100
+ if (self.valueChangeHandler)
101
+ setImmediate(() => self.valueChangeHandler(self.value));
102
+ dialog.dismiss();
103
+ },
104
+ },
105
+ });
106
+ const cancelListener = Java.registerClass({
107
+ name: "com.frida.MultiChoiceCancel" +
108
+ Date.now() +
109
+ Math.random().toString(36).slice(2),
110
+ implements: [DialogClickListener],
111
+ methods: {
112
+ onClick: function (dialog, _which) {
113
+ dialog.dismiss();
114
+ },
115
+ },
116
+ });
117
+ const builder = AlertDialogBuilder.$new(context);
118
+ builder.setTitle(String.$new("请选择"));
119
+ builder.setMultiChoiceItems(csArray, boolArray, multiListener.$new());
120
+ builder.setPositiveButton(String.$new("确定"), okListener.$new());
121
+ builder.setNegativeButton(String.$new("取消"), cancelListener.$new());
122
+ const dialog = builder.create();
123
+ const WindowManagerLP = api_1.API.LayoutParams;
124
+ const BuildVERSION = api_1.API.BuildVERSION;
125
+ const win = dialog.getWindow();
126
+ if (win) {
127
+ if (BuildVERSION.SDK_INT.value >= 26) {
128
+ win.setType(WindowManagerLP.TYPE_APPLICATION_OVERLAY.value);
129
+ }
130
+ else {
131
+ win.setType(WindowManagerLP.TYPE_PHONE.value);
132
+ }
133
+ win.addFlags(WindowManagerLP.FLAG_NOT_FOCUSABLE.value);
134
+ win.addFlags(WindowManagerLP.FLAG_NOT_TOUCH_MODAL.value);
135
+ }
136
+ dialog.show();
137
+ }
138
+ updateView() {
139
+ if (!this.triggerText)
140
+ return;
141
+ Java.scheduleOnMainThread(() => {
142
+ const String = api_1.API.JString;
143
+ this.triggerText.setText(String.$new(this.buildDisplayText() + " ▾"));
144
+ });
145
+ }
146
+ buildDisplayText() {
147
+ const selected = this.getCheckedValues();
148
+ if (selected.length === 0)
149
+ return "请选择";
150
+ const labels = selected.map((x) => x.label);
151
+ if (labels.length <= this.maxDisplayCount)
152
+ return labels.join("、");
153
+ const shown = labels.slice(0, this.maxDisplayCount).join("、");
154
+ const rest = labels.length - this.maxDisplayCount;
155
+ return `${shown} +${rest}`;
156
+ }
157
+ getCheckedValues() {
158
+ return Array.from(this.optionsMap.values()).filter((op) => op.checked);
159
+ }
160
+ setChecked(id, checked) {
161
+ if (!this.optionsMap.has(id)) {
162
+ console.warn(`[CheckBoxGroup:${this.id}] Option with id "${id}" not found`);
163
+ return;
164
+ }
165
+ const opt = this.optionsMap.get(id);
166
+ this.optionsMap.set(id, { ...opt, checked });
167
+ this.value = this.getCheckedValues();
168
+ this.updateView();
169
+ this.emit("change", this.value, { id, checked });
170
+ this.emit("valueChanged", this.value);
171
+ if (this.changeHandler)
172
+ this.changeHandler(this.value, { id: opt.id, checked });
173
+ if (this.valueChangeHandler)
174
+ this.valueChangeHandler(this.value);
175
+ }
176
+ setCheckedValues(checkedIds) {
177
+ for (const [id, opt] of this.optionsMap.entries()) {
178
+ this.optionsMap.set(id, { ...opt, checked: false });
179
+ }
180
+ for (const id of checkedIds) {
181
+ if (this.optionsMap.has(id)) {
182
+ const opt = this.optionsMap.get(id);
183
+ this.optionsMap.set(id, { ...opt, checked: true });
184
+ }
185
+ }
186
+ this.value = this.getCheckedValues();
187
+ this.updateView();
188
+ this.emit("change", this.value);
189
+ this.emit("valueChanged", this.value);
190
+ if (this.changeHandler)
191
+ this.changeHandler(this.value);
192
+ if (this.valueChangeHandler)
193
+ this.valueChangeHandler(this.value);
194
+ }
195
+ getOptions() {
196
+ return Array.from(this.optionsMap.values()).slice();
197
+ }
198
+ }
199
+ exports.CheckBoxGroup = CheckBoxGroup;
@@ -0,0 +1,19 @@
1
+ import { UIComponent } from "./ui-components";
2
+ export declare class Collapsible extends UIComponent {
3
+ private title;
4
+ private expanded;
5
+ private contentContainer;
6
+ private arrowView;
7
+ pendingChildren: UIComponent[];
8
+ constructor(id: string, title: string, expanded?: boolean);
9
+ protected createView(context: any): void;
10
+ protected updateView(): void;
11
+ toggle(): void;
12
+ expand(): void;
13
+ collapse(): void;
14
+ setTitle(title: string): void;
15
+ addChild(component: UIComponent): void;
16
+ addChildren(components: UIComponent[]): void;
17
+ removeChildView(view: any): void;
18
+ clearChildren(): void;
19
+ }
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Collapsible = void 0;
4
+ const api_1 = require("../api");
5
+ const ui_components_1 = require("./ui-components");
6
+ const style_1 = require("./style/style");
7
+ class Collapsible extends ui_components_1.UIComponent {
8
+ constructor(id, title, expanded = false) {
9
+ super(id);
10
+ this.pendingChildren = [];
11
+ this.title = title;
12
+ this.expanded = expanded;
13
+ this.value = expanded;
14
+ }
15
+ createView(context) {
16
+ const LinearLayout = api_1.API.LinearLayout;
17
+ const TextView = api_1.API.TextView;
18
+ const String = api_1.API.JString;
19
+ const ViewGroupLayoutParams = api_1.API.ViewGroupLayoutParams;
20
+ const LinearLayoutParams = api_1.API.LinearLayoutParams;
21
+ const View = api_1.API.View;
22
+ const Gravity = api_1.API.Gravity;
23
+ const container = LinearLayout.$new(context);
24
+ container.setOrientation(LinearLayout.VERTICAL.value);
25
+ container.setLayoutParams(LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
26
+ (0, style_1.applyStyle)(container, "card", this.menu.options.theme);
27
+ const titleRow = LinearLayout.$new(context);
28
+ titleRow.setOrientation(LinearLayout.HORIZONTAL.value);
29
+ titleRow.setGravity(Gravity.CENTER_VERTICAL.value);
30
+ titleRow.setLayoutParams(LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
31
+ (0, style_1.applyStyle)(titleRow, "row", this.menu.options.theme);
32
+ const arrowText = this.expanded ? "▼" : "▶";
33
+ const arrowTextView = TextView.$new(context);
34
+ arrowTextView.setText(String.$new(arrowText));
35
+ arrowTextView.setSingleLine(true);
36
+ (0, style_1.applyStyle)(arrowTextView, "caption", this.menu.options.theme);
37
+ arrowTextView.setPadding(0, 0, (0, style_1.dp)(context, 8), 0);
38
+ this.arrowView = arrowTextView;
39
+ const titleView = TextView.$new(context);
40
+ titleView.setText(String.$new(this.title));
41
+ titleView.setSingleLine(true);
42
+ (0, style_1.applyStyle)(titleView, "text", this.menu.options.theme);
43
+ titleView.setTypeface(null, 1);
44
+ titleView.setLayoutParams(LinearLayoutParams.$new(0, ViewGroupLayoutParams.WRAP_CONTENT.value, 1.0));
45
+ titleRow.addView(this.arrowView);
46
+ titleRow.addView(titleView);
47
+ this.contentContainer = LinearLayout.$new(context);
48
+ this.contentContainer.setOrientation(LinearLayout.VERTICAL.value);
49
+ this.contentContainer.setLayoutParams(LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
50
+ this.contentContainer.setPadding((0, style_1.dp)(context, 2), (0, style_1.dp)(context, 2), (0, style_1.dp)(context, 2), (0, style_1.dp)(context, 4));
51
+ if (this.expanded) {
52
+ this.contentContainer.setVisibility(View.VISIBLE.value);
53
+ }
54
+ else {
55
+ this.contentContainer.setVisibility(View.GONE.value);
56
+ }
57
+ container.addView(titleRow);
58
+ container.addView(this.contentContainer);
59
+ this.view = container;
60
+ if (this.pendingChildren.length > 0) {
61
+ const ctx = this.view.getContext();
62
+ for (const c of this.pendingChildren) {
63
+ try {
64
+ c.init(ctx);
65
+ const v = c.getView();
66
+ if (v)
67
+ this.contentContainer.addView(v);
68
+ }
69
+ catch (e) { }
70
+ }
71
+ this.pendingChildren = [];
72
+ }
73
+ this.view.titleRow = titleRow;
74
+ this.view.titleView = titleView;
75
+ this.view.contentContainer = this.contentContainer;
76
+ const OnClickListener = api_1.API.OnClickListener;
77
+ const self = this;
78
+ const clickListener = Java.registerClass({
79
+ name: "com.frida.CollapsibleClickListener" +
80
+ Date.now() +
81
+ Math.random().toString(36).substring(6),
82
+ implements: [OnClickListener],
83
+ methods: {
84
+ onClick: function () {
85
+ self.toggle();
86
+ },
87
+ },
88
+ });
89
+ titleRow.setOnClickListener(clickListener.$new());
90
+ }
91
+ updateView() {
92
+ if (!this.view) {
93
+ console.warn(`[Collapsible:${this.id}] Cannot update view - view not initialized`);
94
+ return;
95
+ }
96
+ this.expanded = this.value;
97
+ Java.scheduleOnMainThread(() => {
98
+ const View = api_1.API.View;
99
+ const String = api_1.API.JString;
100
+ const contentContainer = this.view.contentContainer;
101
+ if (contentContainer) {
102
+ contentContainer.setVisibility(this.expanded ? View.VISIBLE.value : View.GONE.value);
103
+ }
104
+ if (this.arrowView) {
105
+ const arrowText = this.expanded ? "▼" : "▶";
106
+ this.arrowView.setText(String.$new(arrowText));
107
+ }
108
+ });
109
+ }
110
+ toggle() {
111
+ this.value = !this.value;
112
+ this.updateView();
113
+ this.emit("toggle", this.value);
114
+ }
115
+ expand() {
116
+ this.value = true;
117
+ this.updateView();
118
+ this.emit("expand");
119
+ }
120
+ collapse() {
121
+ this.value = false;
122
+ this.updateView();
123
+ this.emit("collapse");
124
+ }
125
+ setTitle(title) {
126
+ this.title = title;
127
+ if (!this.view) {
128
+ console.warn(`[Collapsible:${this.id}] Cannot set title - view not initialized`);
129
+ return;
130
+ }
131
+ Java.scheduleOnMainThread(() => {
132
+ const titleView = this.view.titleView;
133
+ if (titleView) {
134
+ const String = api_1.API.JString;
135
+ titleView.setText(String.$new(title));
136
+ }
137
+ });
138
+ }
139
+ addChild(component) {
140
+ if (!this.contentContainer || !this.view) {
141
+ this.pendingChildren.push(component);
142
+ return;
143
+ }
144
+ Java.scheduleOnMainThread(() => {
145
+ try {
146
+ const ctx = this.view.getContext();
147
+ component.init(ctx);
148
+ const v = component.getView();
149
+ if (v)
150
+ this.contentContainer.addView(v);
151
+ }
152
+ catch (e) { }
153
+ });
154
+ }
155
+ addChildren(components) {
156
+ for (const c of components)
157
+ this.addChild(c);
158
+ }
159
+ removeChildView(view) {
160
+ if (!this.contentContainer)
161
+ return;
162
+ Java.scheduleOnMainThread(() => {
163
+ try {
164
+ this.contentContainer.removeView(view);
165
+ }
166
+ catch (_e) { }
167
+ });
168
+ }
169
+ clearChildren() {
170
+ if (!this.contentContainer)
171
+ return;
172
+ Java.scheduleOnMainThread(() => {
173
+ this.contentContainer.removeAllViews();
174
+ });
175
+ }
176
+ }
177
+ exports.Collapsible = Collapsible;
@@ -0,0 +1,18 @@
1
+ import { UIComponent } from "./ui-components";
2
+ export declare class ImageView extends UIComponent {
3
+ private source;
4
+ private width;
5
+ private height;
6
+ static LayoutParamsEnum: {
7
+ readonly WRAP_CONTENT: number;
8
+ readonly MATCH_PARENT: number;
9
+ };
10
+ constructor(id: string, source: string | number, width: (typeof ImageView.LayoutParamsEnum)[keyof typeof ImageView.LayoutParamsEnum] | number, height: (typeof ImageView.LayoutParamsEnum)[keyof typeof ImageView.LayoutParamsEnum] | number);
11
+ protected createView(context: any): void;
12
+ private loadImage;
13
+ protected updateView(): void;
14
+ private updateSize;
15
+ setImage(source: string | number): void;
16
+ setScaleType(scaleType: any): void;
17
+ setSize(width: number, height: number): void;
18
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ImageView = void 0;
4
+ const api_1 = require("../api");
5
+ const ui_components_1 = require("./ui-components");
6
+ class ImageView extends ui_components_1.UIComponent {
7
+ constructor(id, source, width, height) {
8
+ super(id);
9
+ this.source = source;
10
+ this.width = width;
11
+ this.height = height;
12
+ this.value = source;
13
+ }
14
+ createView(context) {
15
+ const imageView = api_1.API.ImageView;
16
+ const imageViewScaleType = api_1.API.ImageViewScaleType;
17
+ const Color = api_1.API.Color;
18
+ const ViewGroupLayoutParams = api_1.API.ViewGroupLayoutParams;
19
+ this.view = imageView.$new(context);
20
+ this.view.setScaleType(imageViewScaleType.FIT_CENTER.value);
21
+ this.view.setBackgroundColor(Color.TRANSPARENT.value);
22
+ const layoutParams = ViewGroupLayoutParams.$new(this.width, this.height);
23
+ this.view.setLayoutParams(layoutParams);
24
+ this.loadImage(this.source);
25
+ }
26
+ loadImage(source) {
27
+ Java.scheduleOnMainThread(() => {
28
+ try {
29
+ const Base64 = api_1.API.Base64;
30
+ const BitmapFactory = api_1.API.BitmapFactory;
31
+ const decoded = Base64.decode(source, Base64.DEFAULT.value);
32
+ const bitmap = BitmapFactory.decodeByteArray(decoded, 0, decoded.length);
33
+ this.view.setImageBitmap(bitmap);
34
+ }
35
+ catch (error) {
36
+ console.error(`[Image:${this.id}] Failed to load image:`, error);
37
+ }
38
+ });
39
+ }
40
+ updateView() {
41
+ if (!this.view) {
42
+ console.warn(`[Image:${this.id}] Cannot update view - view not initialized`);
43
+ return;
44
+ }
45
+ this.loadImage(this.source);
46
+ this.updateSize();
47
+ }
48
+ updateSize() {
49
+ const ViewGroupLayoutParams = api_1.API.ViewGroupLayoutParams;
50
+ const layoutParams = this.view.getLayoutParams();
51
+ if (layoutParams) {
52
+ layoutParams.width = this.width;
53
+ layoutParams.height = this.height;
54
+ this.view.setLayoutParams(layoutParams);
55
+ }
56
+ else {
57
+ const newParams = ViewGroupLayoutParams.$new(this.width, this.height);
58
+ this.view.setLayoutParams(newParams);
59
+ }
60
+ }
61
+ setImage(source) {
62
+ this.source = source;
63
+ this.value = source;
64
+ this.updateView();
65
+ }
66
+ setScaleType(scaleType) {
67
+ if (this.view) {
68
+ Java.scheduleOnMainThread(() => {
69
+ this.view.setScaleType(scaleType);
70
+ });
71
+ }
72
+ }
73
+ setSize(width, height) {
74
+ this.width = width;
75
+ this.height = height;
76
+ if (this.view) {
77
+ Java.scheduleOnMainThread(() => {
78
+ this.updateSize();
79
+ });
80
+ }
81
+ }
82
+ }
83
+ exports.ImageView = ImageView;
84
+ ImageView.LayoutParamsEnum = {
85
+ WRAP_CONTENT: api_1.API.ViewGroupLayoutParams.WRAP_CONTENT.value,
86
+ MATCH_PARENT: api_1.API.ViewGroupLayoutParams.MATCH_PARENT.value,
87
+ };
@@ -0,0 +1,33 @@
1
+ import { UIComponent } from "./ui-components";
2
+ export declare class NumberInput extends UIComponent {
3
+ private text;
4
+ private hint;
5
+ private min;
6
+ private max;
7
+ private handler?;
8
+ private title;
9
+ constructor(id: string, initialValue?: number, min?: number | null, max?: number | null, text?: string, hint?: string, title?: string);
10
+ protected updateView(): void;
11
+ getValue(): number;
12
+ protected createView(context: any): void;
13
+ private showDialog;
14
+ setOnValueChange(handler: (value: number) => void): void;
15
+ private applyConstraints;
16
+ setHint(hint: string): void;
17
+ setConstraints(min: number | null, max: number | null): void;
18
+ getNumber(): number;
19
+ setNumber(value: number): void;
20
+ }
21
+ export declare class TextInput extends UIComponent {
22
+ private text;
23
+ private hint;
24
+ private handler?;
25
+ private title;
26
+ constructor(id: string, initialValue?: string, text?: string, hint?: string, title?: string);
27
+ protected updateView(): void;
28
+ protected createView(context: any): void;
29
+ protected emitValue(value: any): void;
30
+ setOnValueChange(handler: (value: string) => void): void;
31
+ private showDialog;
32
+ setText(text: string): void;
33
+ }