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,346 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TextInput = exports.NumberInput = 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 NumberInput extends ui_components_1.UIComponent {
8
+ constructor(id, initialValue = 0, min = null, max = null, text = "单击输入数值", hint = "请输入数值", title = "请输入") {
9
+ super(id);
10
+ this.value = initialValue;
11
+ this.text = text;
12
+ this.hint = hint;
13
+ this.min = min;
14
+ this.max = max;
15
+ this.title = title;
16
+ }
17
+ updateView() {
18
+ if (!this.view) {
19
+ console.warn(`[Switch:${this.id}] Cannot update view - view not initialized`);
20
+ return;
21
+ }
22
+ Java.scheduleOnMainThread(() => {
23
+ const String = api_1.API.JString;
24
+ this.view.setText(String.$new(`${this.text}: ${this.value}`));
25
+ });
26
+ }
27
+ getValue() {
28
+ return this.value;
29
+ }
30
+ createView(context) {
31
+ const Button = api_1.API.Button;
32
+ const String = api_1.API.JString;
33
+ this.view = Button.$new(context);
34
+ this.view.setText(String.$new(`${this.text}: ${this.value}`));
35
+ (0, style_1.applyStyle)(this.view, "inputTrigger", this.menu.options.theme);
36
+ const self = this;
37
+ this.view.setOnClickListener(Java.registerClass({
38
+ name: "com.frida.NumberInputClick" +
39
+ Date.now() +
40
+ Math.random().toString(36).substring(6),
41
+ implements: [api_1.API.OnClickListener],
42
+ methods: {
43
+ onClick: function (v) {
44
+ self.showDialog(context);
45
+ },
46
+ },
47
+ }).$new());
48
+ }
49
+ showDialog(context) {
50
+ Java.scheduleOnMainThread(() => {
51
+ const AlertDialogBuilder = api_1.API.AlertDialogBuilder;
52
+ const EditText = api_1.API.EditText;
53
+ const String = api_1.API.JString;
54
+ const TextViewBufferType = api_1.API.TextViewBufferType;
55
+ const InputType = api_1.API.InputType;
56
+ const LayoutParams = api_1.API.LayoutParams;
57
+ const LinearLayoutParams = api_1.API.LinearLayoutParams;
58
+ const ViewGroupLayoutParams = api_1.API.ViewGroupLayoutParams;
59
+ const builder = AlertDialogBuilder.$new(context);
60
+ builder.setTitle(String.$new(this.title));
61
+ const input = EditText.$new(context);
62
+ (0, style_1.applyEditTextStyle)(input, this.menu.options.theme);
63
+ input.setHint(String.$new(this.hint));
64
+ input.setText(String.$new(this.value + ""), TextViewBufferType.NORMAL.value);
65
+ input.setInputType(InputType.TYPE_CLASS_NUMBER.value |
66
+ InputType.TYPE_NUMBER_FLAG_DECIMAL.value |
67
+ InputType.TYPE_NUMBER_FLAG_SIGNED.value);
68
+ const lp = LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value);
69
+ input.setLayoutParams(lp);
70
+ const LinearLayout = api_1.API.LinearLayout;
71
+ const container = LinearLayout.$new(context);
72
+ container.setPadding((0, style_1.dp)(context, 16), (0, style_1.dp)(context, 10), (0, style_1.dp)(context, 16), (0, style_1.dp)(context, 6));
73
+ container.addView(input);
74
+ builder.setView(container);
75
+ const self = this;
76
+ builder.setPositiveButton(String.$new("确认"), Java.registerClass({
77
+ name: "com.frida.NumberInputOK" +
78
+ Date.now() +
79
+ Math.random().toString(36).substring(6),
80
+ implements: [api_1.API.DialogInterfaceOnClickListener],
81
+ methods: {
82
+ onClick: function (_dialog, _which) {
83
+ const text = Java.cast(input.getText(), Java.use("java.lang.CharSequence")).toString() + "";
84
+ if (text === "") {
85
+ self.value = 0;
86
+ }
87
+ else {
88
+ const num = parseFloat(text);
89
+ if (!isNaN(num))
90
+ self.value = num;
91
+ else
92
+ return;
93
+ }
94
+ self.applyConstraints();
95
+ self.view.setText(String.$new(`${self.text}: ${self.value}`));
96
+ self.emit("valueChanged", self.value);
97
+ if (self.handler)
98
+ self.handler(self.value);
99
+ },
100
+ },
101
+ }).$new());
102
+ builder.setNegativeButton(String.$new("取消"), null);
103
+ const dialog = builder.create();
104
+ const window = dialog.getWindow();
105
+ const BuildVERSION = api_1.API.BuildVERSION;
106
+ if (window) {
107
+ if (BuildVERSION.SDK_INT.value >= 26) {
108
+ window.setType(LayoutParams.TYPE_APPLICATION_OVERLAY.value);
109
+ }
110
+ else {
111
+ window.setType(LayoutParams.TYPE_PHONE.value);
112
+ }
113
+ }
114
+ dialog.show();
115
+ try {
116
+ const bg = api_1.API.GradientDrawable.$new();
117
+ bg.setColor(this.menu.options.theme.colors.cardBg);
118
+ bg.setCornerRadius((0, style_1.dp)(context, 14));
119
+ bg.setStroke((0, style_1.dp)(context, 1), this.menu.options.theme.colors.divider);
120
+ const win = dialog.getWindow();
121
+ if (win) {
122
+ const decor = win.getDecorView();
123
+ decor.setBackground(bg);
124
+ decor.setPadding((0, style_1.dp)(context, 12), (0, style_1.dp)(context, 12), (0, style_1.dp)(context, 12), (0, style_1.dp)(context, 12));
125
+ }
126
+ const AlertDialog = api_1.API.AlertDialog;
127
+ const ad = Java.cast(dialog, AlertDialog);
128
+ const BUTTON_POSITIVE = -1;
129
+ const BUTTON_NEGATIVE = -2;
130
+ const pos = ad.getButton(BUTTON_POSITIVE);
131
+ const neg = ad.getButton(BUTTON_NEGATIVE);
132
+ if (pos) {
133
+ pos.setAllCaps(false);
134
+ pos.setTextColor(this.menu.options.theme.colors.accent);
135
+ pos.setPadding((0, style_1.dp)(context, 10), (0, style_1.dp)(context, 8), (0, style_1.dp)(context, 10), (0, style_1.dp)(context, 8));
136
+ }
137
+ if (neg) {
138
+ neg.setAllCaps(false);
139
+ neg.setTextColor(this.menu.options.theme.colors.subText);
140
+ neg.setPadding((0, style_1.dp)(context, 10), (0, style_1.dp)(context, 8), (0, style_1.dp)(context, 10), (0, style_1.dp)(context, 8));
141
+ }
142
+ }
143
+ catch (e) {
144
+ }
145
+ try {
146
+ const titleId = context
147
+ .getResources()
148
+ .getIdentifier(Java.use("java.lang.String").$new("alertTitle"), Java.use("java.lang.String").$new("id"), Java.use("java.lang.String").$new("android"));
149
+ if (titleId && titleId !== 0) {
150
+ const tv = dialog.findViewById(titleId);
151
+ if (tv) {
152
+ const TextView = api_1.API.TextView;
153
+ const t = Java.cast(tv, TextView);
154
+ t.setTextColor(this.menu.options.theme.colors.text);
155
+ }
156
+ }
157
+ }
158
+ catch (e) {
159
+ console.error(e);
160
+ }
161
+ });
162
+ }
163
+ setOnValueChange(handler) {
164
+ this.handler = handler;
165
+ }
166
+ applyConstraints() {
167
+ let constrained = this.value;
168
+ if (this.min !== null)
169
+ constrained = Math.max(this.min, constrained);
170
+ if (this.max !== null)
171
+ constrained = Math.min(this.max, constrained);
172
+ this.value = constrained;
173
+ }
174
+ setHint(hint) {
175
+ this.hint = hint;
176
+ }
177
+ setConstraints(min, max) {
178
+ this.min = min;
179
+ this.max = max;
180
+ this.applyConstraints();
181
+ }
182
+ getNumber() {
183
+ return this.value;
184
+ }
185
+ setNumber(value) {
186
+ this.value = value;
187
+ this.applyConstraints();
188
+ }
189
+ }
190
+ exports.NumberInput = NumberInput;
191
+ class TextInput extends ui_components_1.UIComponent {
192
+ constructor(id, initialValue = "", text = "单击输入文本", hint = "请输入文本", title = "请输入") {
193
+ super(id);
194
+ this.text = text;
195
+ this.hint = hint;
196
+ this.value = initialValue;
197
+ this.title = title;
198
+ }
199
+ updateView() {
200
+ if (!this.view) {
201
+ console.warn(`[Switch:${this.id}] Cannot update view - view not initialized`);
202
+ return;
203
+ }
204
+ Java.scheduleOnMainThread(() => {
205
+ const String = api_1.API.JString;
206
+ this.view.setText(String.$new(`${this.text}: ${this.value}`));
207
+ });
208
+ }
209
+ createView(context) {
210
+ const Button = api_1.API.Button;
211
+ const String = api_1.API.JString;
212
+ this.view = Button.$new(context);
213
+ (0, style_1.applyStyle)(this.view, "inputTrigger", this.menu.options.theme);
214
+ this.view.setText(String.$new(`${this.text}: ${this.value}`));
215
+ const self = this;
216
+ this.view.setOnClickListener(Java.registerClass({
217
+ name: "com.frida.AlertTextInputClick" +
218
+ Date.now() +
219
+ Math.random().toString(36).substring(6),
220
+ implements: [api_1.API.OnClickListener],
221
+ methods: {
222
+ onClick: function (v) {
223
+ self.showDialog(context);
224
+ },
225
+ },
226
+ }).$new());
227
+ }
228
+ emitValue(value) {
229
+ this.emit("valueChanged", value);
230
+ }
231
+ setOnValueChange(handler) {
232
+ this.handler = handler;
233
+ }
234
+ showDialog(context) {
235
+ Java.scheduleOnMainThread(() => {
236
+ const AlertDialogBuilder = api_1.API.AlertDialogBuilder;
237
+ const EditText = api_1.API.EditText;
238
+ const String = api_1.API.JString;
239
+ const TextViewBufferType = api_1.API.TextViewBufferType;
240
+ const builder = AlertDialogBuilder.$new(context);
241
+ const LinearLayoutParams = api_1.API.LinearLayoutParams;
242
+ const ViewGroupLayoutParams = api_1.API.ViewGroupLayoutParams;
243
+ const input = EditText.$new(context);
244
+ const LinearLayout = api_1.API.LinearLayout;
245
+ (0, style_1.applyEditTextStyle)(input, this.menu.options.theme);
246
+ input.setHint(String.$new(this.hint));
247
+ input.setText(String.$new(this.value), TextViewBufferType.NORMAL.value);
248
+ builder.setTitle(String.$new(this.title));
249
+ const lp = LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value);
250
+ input.setLayoutParams(lp);
251
+ const container = LinearLayout.$new(context);
252
+ container.setPadding((0, style_1.dp)(context, 16), (0, style_1.dp)(context, 10), (0, style_1.dp)(context, 16), (0, style_1.dp)(context, 6));
253
+ container.addView(input);
254
+ builder.setView(container);
255
+ const self = this;
256
+ builder.setPositiveButton(String.$new("确认"), Java.registerClass({
257
+ name: "com.frida.AlertTextInputOK" +
258
+ Date.now() +
259
+ Math.random().toString(36).substring(6),
260
+ implements: [api_1.API.DialogInterfaceOnClickListener],
261
+ methods: {
262
+ onClick: function (dialog, which) {
263
+ const text = Java.cast(input.getText(), Java.use("java.lang.CharSequence")).toString() + "";
264
+ self.value = text.trim();
265
+ self.view.setText(String.$new(`${self.text}: ${self.value}`));
266
+ self.emit("valueChanged", text);
267
+ if (self.handler)
268
+ self.handler(text);
269
+ },
270
+ },
271
+ }).$new());
272
+ builder.setNegativeButton(String.$new("取消"), null);
273
+ const LayoutParams = api_1.API.LayoutParams;
274
+ const dialog = builder.create();
275
+ const bg = api_1.API.GradientDrawable.$new();
276
+ bg.setColor(this.menu.options.theme.colors.cardBg);
277
+ bg.setCornerRadius((0, style_1.dp)(context, 14));
278
+ bg.setStroke((0, style_1.dp)(context, 1), this.menu.options.theme.colors.divider);
279
+ const window = dialog.getWindow();
280
+ const BuildVERSION = api_1.API.BuildVERSION;
281
+ if (window) {
282
+ if (BuildVERSION.SDK_INT.value >= 26) {
283
+ window.setType(LayoutParams.TYPE_APPLICATION_OVERLAY.value);
284
+ }
285
+ else {
286
+ window.setType(LayoutParams.TYPE_PHONE.value);
287
+ }
288
+ }
289
+ dialog.show();
290
+ try {
291
+ const decor = dialog.getWindow().getDecorView();
292
+ decor.setBackground(bg);
293
+ decor.setPadding((0, style_1.dp)(context, 12), (0, style_1.dp)(context, 12), (0, style_1.dp)(context, 12), (0, style_1.dp)(context, 12));
294
+ }
295
+ catch (e) {
296
+ console.error(e);
297
+ }
298
+ try {
299
+ const AlertDialog = api_1.API.AlertDialog;
300
+ const ad = Java.cast(dialog, AlertDialog);
301
+ const BUTTON_POSITIVE = -1;
302
+ const BUTTON_NEGATIVE = -2;
303
+ const pos = ad.getButton(BUTTON_POSITIVE);
304
+ const neg = ad.getButton(BUTTON_NEGATIVE);
305
+ if (pos) {
306
+ pos.setAllCaps(false);
307
+ pos.setTextColor(this.menu.options.theme.colors.accent);
308
+ pos.setPadding((0, style_1.dp)(context, 10), (0, style_1.dp)(context, 8), (0, style_1.dp)(context, 10), (0, style_1.dp)(context, 8));
309
+ }
310
+ if (neg) {
311
+ neg.setAllCaps(false);
312
+ neg.setTextColor(this.menu.options.theme.colors.subText);
313
+ neg.setPadding((0, style_1.dp)(context, 10), (0, style_1.dp)(context, 8), (0, style_1.dp)(context, 10), (0, style_1.dp)(context, 8));
314
+ }
315
+ }
316
+ catch (e) {
317
+ console.error(e);
318
+ }
319
+ try {
320
+ const titleId = context
321
+ .getResources()
322
+ .getIdentifier(Java.use("java.lang.String").$new("alertTitle"), Java.use("java.lang.String").$new("id"), Java.use("java.lang.String").$new("android"));
323
+ if (titleId && titleId !== 0) {
324
+ const tv = dialog.findViewById(titleId);
325
+ if (tv) {
326
+ const TextView = api_1.API.TextView;
327
+ const t = Java.cast(tv, TextView);
328
+ t.setTextColor(this.menu.options.theme.colors.text);
329
+ }
330
+ }
331
+ }
332
+ catch (e) {
333
+ console.error(e);
334
+ }
335
+ });
336
+ }
337
+ setText(text) {
338
+ if (this.view) {
339
+ Java.scheduleOnMainThread(() => {
340
+ const String = api_1.API.JString;
341
+ this.view.setText(String.$new(text));
342
+ });
343
+ }
344
+ }
345
+ }
346
+ exports.TextInput = TextInput;
@@ -0,0 +1,22 @@
1
+ import { UIComponent } from "./ui-components";
2
+ export declare class Selector extends UIComponent {
3
+ private items;
4
+ private selectedIndex;
5
+ private handler?;
6
+ constructor(id: string, items: {
7
+ lable: string;
8
+ [key: string]: any;
9
+ }[], selectedIndex?: number);
10
+ getValue(): {
11
+ lable: string;
12
+ [key: string]: any;
13
+ };
14
+ protected createView(context: any): void;
15
+ onValueChange(handler: (value: any) => {}): void;
16
+ protected updateView(): void;
17
+ setItems(items: {
18
+ lable: string;
19
+ [key: string]: any;
20
+ }[]): void;
21
+ getSelectedIndex(): number;
22
+ }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Selector = void 0;
4
+ const api_1 = require("../api");
5
+ const ui_components_1 = require("./ui-components");
6
+ class Selector extends ui_components_1.UIComponent {
7
+ constructor(id, items, selectedIndex = 0) {
8
+ super(id);
9
+ this.items = items;
10
+ this.selectedIndex = selectedIndex;
11
+ this.value = items[selectedIndex];
12
+ }
13
+ getValue() {
14
+ return this.value;
15
+ }
16
+ createView(context) {
17
+ const Spinner = api_1.API.Spinner;
18
+ const ArrayAdapter = api_1.API.ArrayAdapter;
19
+ const String = api_1.API.JString;
20
+ const R_layout = api_1.API.R_layout;
21
+ this.view = Spinner.$new(context);
22
+ this.view.setBackgroundColor(0xff555555 | 0);
23
+ const javaItems = this.items.map((item) => String.$new(item.lable));
24
+ const adapter = ArrayAdapter.$new(context, R_layout.simple_spinner_item.value, Java.array("java.lang.CharSequence", javaItems));
25
+ adapter.setDropDownViewResource(R_layout.simple_spinner_dropdown_item.value);
26
+ this.view.setAdapter(adapter);
27
+ this.view.setSelection(this.selectedIndex);
28
+ try {
29
+ this.view.setPopupBackgroundResource(0xff333333 | 0);
30
+ }
31
+ catch (e) {
32
+ }
33
+ const AdapterViewOnItemSelectedListener = api_1.API.AdapterViewOnItemSelectedListener;
34
+ const self = this;
35
+ const itemSelectedListener = Java.registerClass({
36
+ name: "com.frida.MyItemSelectedListener" +
37
+ Date.now() +
38
+ Math.random().toString(36).substring(6),
39
+ implements: [AdapterViewOnItemSelectedListener],
40
+ methods: {
41
+ onItemSelected: function (parent, view, position, id) {
42
+ self.selectedIndex = position;
43
+ self.value = self.items[position];
44
+ self.emit("valueChanged", self.value);
45
+ if (self.handler)
46
+ setImmediate(() => self.handler(self.value));
47
+ },
48
+ onNothingSelected: function (parent) {
49
+ },
50
+ },
51
+ });
52
+ this.view.setOnItemSelectedListener(itemSelectedListener.$new());
53
+ }
54
+ onValueChange(handler) {
55
+ this.handler = handler;
56
+ }
57
+ updateView() {
58
+ if (!this.view) {
59
+ console.warn(`[Selector:${this.id}] Cannot update view - view not initialized`);
60
+ return;
61
+ }
62
+ const index = this.items.findIndex((value) => value.lable == this.value.lable);
63
+ if (index !== -1) {
64
+ Java.scheduleOnMainThread(() => {
65
+ this.view.setSelection(index);
66
+ });
67
+ }
68
+ }
69
+ setItems(items) {
70
+ this.items = items;
71
+ if (!this.view) {
72
+ console.warn(`[Selector:${this.id}] Cannot set items - view not initialized`);
73
+ return;
74
+ }
75
+ Java.scheduleOnMainThread(() => {
76
+ try {
77
+ const ArrayAdapter = api_1.API.ArrayAdapter;
78
+ const context = this.view.getContext();
79
+ const R_layout = api_1.API.R_layout;
80
+ const String = api_1.API.JString;
81
+ const javaItems = items.map((item) => String.$new(item.lable));
82
+ const adapter = ArrayAdapter.$new(context, R_layout.simple_spinner_item.value, Java.array("java.lang.CharSequence", javaItems));
83
+ adapter.setDropDownViewResource(R_layout.simple_spinner_dropdown_item.value);
84
+ this.view.setAdapter(adapter);
85
+ }
86
+ catch (error) {
87
+ console.error(`[Selector:${this.id}] Failed to set items:`, error);
88
+ }
89
+ });
90
+ }
91
+ getSelectedIndex() {
92
+ return this.selectedIndex;
93
+ }
94
+ }
95
+ exports.Selector = Selector;
@@ -0,0 +1,18 @@
1
+ import { UIComponent } from "./ui-components";
2
+ export declare class Slider extends UIComponent {
3
+ private min;
4
+ private max;
5
+ private step;
6
+ private label;
7
+ private handler?;
8
+ constructor(id: string, label: string, min: number, max: number, initialValue?: number, step?: number);
9
+ protected createView(context: any): void;
10
+ setOnValueChange(handler: (value: number) => void): void;
11
+ protected updateView(): void;
12
+ setLabel(label: string): void;
13
+ setRange(min: number, max: number, step?: number): void;
14
+ private calculateSeekBarMax;
15
+ private valueToProgress;
16
+ private progressToValue;
17
+ private clampToStep;
18
+ }
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Slider = void 0;
4
+ const api_1 = require("../api");
5
+ const ui_components_1 = require("./ui-components");
6
+ class Slider extends ui_components_1.UIComponent {
7
+ constructor(id, label, min, max, initialValue = min, step = 1) {
8
+ super(id);
9
+ this.label = label;
10
+ this.min = min;
11
+ this.max = max;
12
+ this.step = step;
13
+ this.value = this.clampToStep(initialValue);
14
+ }
15
+ createView(context) {
16
+ const LinearLayout = api_1.API.LinearLayout;
17
+ const TextView = api_1.API.TextView;
18
+ const SeekBar = api_1.API.SeekBar;
19
+ const Color = api_1.API.Color;
20
+ const String = api_1.API.JString;
21
+ const ViewGroupLayoutParams = api_1.API.ViewGroupLayoutParams;
22
+ const LinearLayoutParams = api_1.API.LinearLayoutParams;
23
+ const container = LinearLayout.$new(context);
24
+ container.setOrientation(0);
25
+ container.setLayoutParams(LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
26
+ container.setPadding(16, 8, 16, 8);
27
+ const labelView = TextView.$new(context);
28
+ labelView.setText(String.$new(this.label));
29
+ labelView.setTextColor(Color.WHITE.value);
30
+ labelView.setTextSize(14);
31
+ labelView.setLayoutParams(LinearLayoutParams.$new(0, ViewGroupLayoutParams.WRAP_CONTENT.value, 1.0));
32
+ const valueView = TextView.$new(context);
33
+ valueView.setText(String.$new(this.value.toString()));
34
+ valueView.setTextColor(Color.WHITE.value);
35
+ valueView.setTextSize(14);
36
+ valueView.setLayoutParams(LinearLayoutParams.$new(ViewGroupLayoutParams.WRAP_CONTENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
37
+ container.addView(labelView);
38
+ container.addView(valueView);
39
+ const seekBar = SeekBar.$new(context);
40
+ seekBar.setMax(this.calculateSeekBarMax());
41
+ seekBar.setProgress(this.valueToProgress(this.value));
42
+ seekBar.setLayoutParams(LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
43
+ const verticalLayout = LinearLayout.$new(context);
44
+ verticalLayout.setOrientation(1);
45
+ verticalLayout.setLayoutParams(LinearLayoutParams.$new(ViewGroupLayoutParams.MATCH_PARENT.value, ViewGroupLayoutParams.WRAP_CONTENT.value));
46
+ verticalLayout.addView(container);
47
+ verticalLayout.addView(seekBar);
48
+ this.view = verticalLayout;
49
+ this.view.seekBar = seekBar;
50
+ this.view.valueView = valueView;
51
+ this.view.labelView = labelView;
52
+ this.view.container = container;
53
+ const SeekBarOnSeekBarChangeListener = api_1.API.SeekBarOnSeekBarChangeListener;
54
+ const self = this;
55
+ const changeListener = Java.registerClass({
56
+ name: "com.frida.MySeekBarChangeListener" +
57
+ Date.now() +
58
+ Math.random().toString(36).substring(6),
59
+ implements: [SeekBarOnSeekBarChangeListener],
60
+ methods: {
61
+ onProgressChanged: function (seekBar, progress, fromUser) {
62
+ if (fromUser) {
63
+ const newValue = self.progressToValue(progress);
64
+ self.value = newValue;
65
+ Java.scheduleOnMainThread(() => {
66
+ const valueView = self.view.valueView;
67
+ if (valueView) {
68
+ valueView.setText(String.$new(newValue.toString()));
69
+ }
70
+ });
71
+ self.emit("valueChanged", newValue);
72
+ if (self.handler)
73
+ setImmediate(() => self.handler(newValue));
74
+ }
75
+ },
76
+ onStartTrackingTouch: function (seekBar) {
77
+ },
78
+ onStopTrackingTouch: function (seekBar) {
79
+ },
80
+ },
81
+ });
82
+ seekBar.setOnSeekBarChangeListener(changeListener.$new());
83
+ }
84
+ setOnValueChange(handler) {
85
+ this.handler = handler;
86
+ }
87
+ updateView() {
88
+ if (!this.view) {
89
+ console.warn(`[Slider:${this.id}] Cannot update view - view not initialized`);
90
+ return;
91
+ }
92
+ Java.scheduleOnMainThread(() => {
93
+ const seekBar = this.view.seekBar;
94
+ const valueView = this.view.valueView;
95
+ if (seekBar) {
96
+ seekBar.setProgress(this.valueToProgress(this.value));
97
+ }
98
+ if (valueView) {
99
+ const String = api_1.API.JString;
100
+ valueView.setText(String.$new(this.value.toString()));
101
+ }
102
+ });
103
+ }
104
+ setLabel(label) {
105
+ this.label = label;
106
+ if (!this.view) {
107
+ console.warn(`[Slider:${this.id}] Cannot set label - view not initialized`);
108
+ return;
109
+ }
110
+ Java.scheduleOnMainThread(() => {
111
+ const labelView = this.view.labelView;
112
+ if (labelView) {
113
+ const String = api_1.API.JString;
114
+ labelView.setText(String.$new(label));
115
+ }
116
+ });
117
+ }
118
+ setRange(min, max, step = 1) {
119
+ this.min = min;
120
+ this.max = max;
121
+ this.step = step;
122
+ this.value = this.clampToStep(this.value);
123
+ if (!this.view) {
124
+ console.warn(`[Slider:${this.id}] Cannot set range - view not initialized`);
125
+ return;
126
+ }
127
+ Java.scheduleOnMainThread(() => {
128
+ const seekBar = this.view.seekBar;
129
+ if (seekBar) {
130
+ seekBar.setMax(this.calculateSeekBarMax());
131
+ seekBar.setProgress(this.valueToProgress(this.value));
132
+ }
133
+ });
134
+ this.updateView();
135
+ }
136
+ calculateSeekBarMax() {
137
+ return Math.round((this.max - this.min) / this.step);
138
+ }
139
+ valueToProgress(value) {
140
+ return Math.round((value - this.min) / this.step);
141
+ }
142
+ progressToValue(progress) {
143
+ const value = this.min + progress * this.step;
144
+ return this.clampToStep(value);
145
+ }
146
+ clampToStep(value) {
147
+ let clamped = Math.max(this.min, Math.min(this.max, value));
148
+ if (this.step > 0) {
149
+ const steps = Math.round((clamped - this.min) / this.step);
150
+ clamped = this.min + steps * this.step;
151
+ }
152
+ return clamped;
153
+ }
154
+ }
155
+ exports.Slider = Slider;
@@ -0,0 +1,5 @@
1
+ import { Theme } from "./theme";
2
+ export type StyleRole = "overlay" | "card" | "category" | "row" | "text" | "caption" | "inputTrigger" | "primaryButton" | "dangerButton" | "headerBar" | "iconButton" | "textButton" | "dangerTextButton" | "divider" | "chip" | "dialog" | "inputField";
3
+ export declare function dp(ctx: any, v: number): number;
4
+ export declare function applyStyle(view: any, role: StyleRole, theme: Theme): void;
5
+ export declare function applyEditTextStyle(editText: any, theme: Theme): void;