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
package/README.md ADDED
@@ -0,0 +1,404 @@
1
+ # Frida Floating Menu UI Library
2
+
3
+ A TypeScript library for creating interactive floating windows on Android devices with UI components (buttons, switches, text, selectors) that can be controlled from JavaScript. Designed for Frida instrumentation and reverse engineering.
4
+
5
+ ## Features
6
+
7
+ - Create floating overlay windows using Android's `WindowManager`
8
+ - Add interactive UI components: Button, Switch, Text label, Selector (dropdown), Slider, Collapsible panel, Category header, TextInput, NumberInput
9
+ - Two-way data binding: JavaScript variables ↔ UI state synchronization
10
+ - Event system for UI interactions (clicks, value changes)
11
+ - Update UI components programmatically from JavaScript
12
+ - Optional log panel to display runtime logs (can be disabled for performance)
13
+ - Set window icon via base64-encoded image
14
+ - Modular, extensible architecture
15
+ - TypeScript support with full type definitions
16
+
17
+ ## Requirements
18
+
19
+ - Frida (tested on Android)
20
+ - Target Android app with overlay permission (`TYPE_APPLICATION_OVERLAY`, API 26+)
21
+ - Frida-compile for TypeScript compilation (included as dev dependency)
22
+
23
+ ## Installation
24
+
25
+ ### As a library in your Frida project
26
+
27
+ 1. Copy the `src/` directory to your project
28
+ 2. Import the library in your TypeScript files:
29
+
30
+ ```typescript
31
+ import { FloatMenu, Button, Switch } from './path/to/src/index';
32
+ ```
33
+
34
+ ### As a standalone package (conceptual)
35
+
36
+ Since this is a library, you typically include the source code in your project rather than installing from npm.
37
+
38
+ ## Quick Start
39
+
40
+ ### 1. Create a TypeScript file (`my-script.ts`)
41
+
42
+ ```typescript
43
+ import { FloatMenu, Button, Switch, Text, Selector } from './src/index';
44
+
45
+ Java.perform(() => {
46
+ // Create floating menu
47
+ const menu = new FloatMenu({
48
+ width: 300,
49
+ height: 400,
50
+ x: 100,
51
+ y: 100,
52
+ showLogs: true
53
+ });
54
+
55
+ menu.show();
56
+
57
+ // Add components
58
+ const button = new Button('myButton', 'Click Me');
59
+ button.setOnClick(() => {
60
+ console.log('Button clicked!');
61
+ });
62
+ menu.addComponent('myButton', button);
63
+
64
+ const switchComp = new Switch('mySwitch', 'Enable Feature', false);
65
+ switchComp.on('valueChanged', (value: boolean) => {
66
+ console.log('Switch:', value);
67
+ });
68
+ menu.addComponent('mySwitch', switchComp);
69
+ });
70
+ ```
71
+
72
+ ### 2. Compile with frida-compile
73
+
74
+ ```bash
75
+ frida-compile my-script.ts -o my-script.js -c
76
+ ```
77
+
78
+ ### 3. Inject into target
79
+
80
+ ```bash
81
+ frida -U -f com.example.app -l my-script.js
82
+ ```
83
+
84
+ ## API Reference
85
+
86
+ ### FloatMenu
87
+
88
+ Main class for creating and managing floating windows.
89
+
90
+ ```typescript
91
+ interface TabDefinition {
92
+ id: string; // Unique tab identifier
93
+ label: string; // Display label for tab button
94
+ }
95
+
96
+ interface FloatMenuOptions {
97
+ width?: number; // Window width (default: 1000)
98
+ height?: number; // Window height (default: 900)
99
+ x?: number; // X position (default: 100)
100
+ y?: number; // Y position (default: 100)
101
+ iconVisible?: boolean; // Show icon initially (default: true)
102
+ iconWidth?: number; // Icon width (default: 200)
103
+ iconHeight?: number; // Icon height (default: 200)
104
+ iconBase64?: string; // Base64-encoded icon image (optional)
105
+ showLogs?: boolean; // Show log panel (default: false)
106
+ logMaxLines?: number; // Max lines in log panel (default: 100)
107
+ title?: string; // Main title text (default: "Frida Float Menu")
108
+ subtitle?: string; // Subtitle text (default: "Interactive Debugging Panel")
109
+ showHeader?: boolean; // Whether to show header (default: true)
110
+ showFooter?: boolean; // Whether to show footer (default: true)
111
+ tabs?: TabDefinition[]; // Tab definitions (optional)
112
+ activeTab?: string; // Initially active tab ID (default: first tab or "default")
113
+ showTabs?: boolean; // Whether to show tab bar (default: true if tabs are defined)
114
+ }
115
+
116
+ class FloatMenu {
117
+ constructor(options?: FloatMenuOptions);
118
+ show(): void; // Display window
119
+ hide(): void; // Hide and destroy window
120
+ addComponent(id: string, component: UIComponent, tabId?: string): void;
121
+ removeComponent(id: string): void;
122
+ getComponent<T extends UIComponent>(id: string): T | undefined;
123
+ setComponentValue(id: string, value: any): void;
124
+ switchTab(tabId: string): void; // Switch to a different tab
125
+ getActiveTabId(): string; // Get currently active tab ID
126
+ on(event: string, callback: (...args: any[]) => void): void;
127
+ off(event: string, callback: (...args: any[]) => void): void;
128
+ setPosition(x: number, y: number): void;
129
+ setSize(width: number, height: number): void;
130
+ clearLogs(): void;
131
+ showIcon(): void; // Minimize to icon
132
+ showMenu(): void; // Expand to menu
133
+ toggleView(): void; // Toggle between icon and menu
134
+ }
135
+ ```
136
+
137
+ ### UI Components
138
+
139
+ All components extend `UIComponent` base class.
140
+
141
+ #### Button
142
+ ```typescript
143
+ class Button extends UIComponent {
144
+ constructor(id: string, label: string);
145
+ setOnClick(handler: () => void): void;
146
+ setLabel(label: string): void;
147
+ // Emits 'click' event
148
+ }
149
+ ```
150
+
151
+ #### Switch
152
+ ```typescript
153
+ class Switch extends UIComponent {
154
+ constructor(id: string, label: string, initialValue?: boolean);
155
+ setLabel(label: string): void;
156
+ // Emits 'valueChanged' event with boolean value
157
+ }
158
+ ```
159
+
160
+ #### Text
161
+ ```typescript
162
+ class Text extends UIComponent {
163
+ constructor(id: string, content: string);
164
+ setText(content: string): void;
165
+ }
166
+ ```
167
+
168
+ #### Selector (Dropdown)
169
+ ```typescript
170
+ class Selector extends UIComponent {
171
+ constructor(id: string, items: string[], selectedIndex?: number);
172
+ setItems(items: string[]): void;
173
+ getSelectedIndex(): number;
174
+ // Emits 'valueChanged' event with selected string
175
+ }
176
+ ```
177
+
178
+ #### Slider (SeekBar)
179
+ ```typescript
180
+ class Slider extends UIComponent {
181
+ constructor(id: string, label: string, min: number, max: number, initialValue?: number, step?: number);
182
+ setLabel(label: string): void;
183
+ setRange(min: number, max: number, step?: number): void;
184
+ // Emits 'valueChanged' event with numeric value
185
+ }
186
+ ```
187
+
188
+ #### Collapsible (Expandable Panel)
189
+ ```typescript
190
+ class Collapsible extends UIComponent {
191
+ constructor(id: string, title: string, expanded?: boolean);
192
+ setTitle(title: string): void;
193
+ toggle(): void; // Toggle expanded/collapsed state
194
+ expand(): void; // Expand panel
195
+ collapse(): void; // Collapse panel
196
+ addChildView(view: any): void; // Add child component view
197
+ removeChildView(view: any): void; // Remove child component view
198
+ clearChildren(): void; // Remove all child views
199
+ // Emits 'toggle', 'expand', 'collapse' events
200
+ }
201
+ ```
202
+
203
+ #### Category (Section Header)
204
+ ```typescript
205
+ class Category extends UIComponent {
206
+ constructor(id: string, label: string);
207
+ setLabel(label: string): void;
208
+ }
209
+ ```
210
+
211
+ #### TextInput (EditText)
212
+ ```typescript
213
+ class TextInput extends UIComponent {
214
+ constructor(id: string, initialValue?: string, hint?: string, multiline?: boolean);
215
+ setHint(hint: string): void;
216
+ setMultiline(multiline: boolean): void;
217
+ getText(): string;
218
+ setText(text: string): void;
219
+ // Emits 'valueChanged' event with string value
220
+ }
221
+ ```
222
+
223
+ #### NumberInput (Numeric EditText)
224
+ ```typescript
225
+ class NumberInput extends UIComponent {
226
+ constructor(id: string, initialValue?: number, hint?: string, min?: number, max?: number, step?: number);
227
+ setHint(hint: string): void;
228
+ setConstraints(min: number | null, max: number | null, step: number | null): void;
229
+ getNumber(): number;
230
+ setNumber(value: number): void;
231
+ // Emits 'valueChanged' event with numeric value
232
+ }
233
+ ```
234
+
235
+ ### Event System
236
+
237
+ Components emit events that can be listened to:
238
+
239
+ ```typescript
240
+ // Component-level events
241
+ component.on('valueChanged', (value) => { /* Switch or Selector value changed */ });
242
+ component.on('click', () => { /* Button clicked */ });
243
+
244
+ // Menu forwards component events with IDs
245
+ menu.on('component:mySwitch:valueChanged', (value) => {
246
+ console.log('Switch with ID "mySwitch" changed to:', value);
247
+ });
248
+
249
+ // Tab change events
250
+ menu.on('tabChanged', (newTabId: string, oldTabId: string) => {
251
+ console.log(`Tab changed from ${oldTabId} to ${newTabId}`);
252
+ });
253
+ ```
254
+
255
+ ### Logger
256
+
257
+ Optional logging system with configurable levels:
258
+
259
+ ```typescript
260
+ import { Logger, LogLevel } from './src/index';
261
+
262
+ const logger = new Logger('debug'); // 'debug' | 'info' | 'warn' | 'error' | 'none'
263
+ logger.info('Message');
264
+ logger.debug('Debug info');
265
+ ```
266
+
267
+ ## Examples
268
+
269
+ ### Basic Example
270
+
271
+ See `example.ts` for a complete TypeScript example with all components.
272
+
273
+ ### Tabbed Interface Example
274
+
275
+ Create a floating menu with multiple tabs:
276
+
277
+ ```typescript
278
+ const menu = new FloatMenu({
279
+ width: 1000,
280
+ height: 900,
281
+ tabs: [
282
+ { id: "controls", label: "Controls" },
283
+ { id: "settings", label: "Settings" },
284
+ { id: "info", label: "Info" }
285
+ ],
286
+ activeTab: "controls",
287
+ showTabs: true,
288
+ title: "Multi-tab Menu",
289
+ subtitle: "Organize your UI in tabs"
290
+ });
291
+
292
+ menu.show();
293
+
294
+ // Add components to specific tabs
295
+ const button = new Button("btn1", "Click Me");
296
+ menu.addComponent("btn1", button, "controls");
297
+
298
+ const switchComp = new Switch("switch1", "Enable", false);
299
+ menu.addComponent("switch1", switchComp, "settings");
300
+
301
+ // Listen for tab changes
302
+ menu.on("tabChanged", (newTabId, oldTabId) => {
303
+ console.log(`Tab changed: ${oldTabId} -> ${newTabId}`);
304
+ });
305
+
306
+ // Switch tabs programmatically
307
+ menu.switchTab("settings");
308
+ ```
309
+
310
+ ### Global Attachment (for simple scripts)
311
+
312
+ If you prefer global variables instead of imports:
313
+
314
+ ```typescript
315
+ import { attachToGlobal } from './src/index';
316
+ attachToGlobal(globalThis);
317
+
318
+ // Now classes are available globally
319
+ Java.perform(() => {
320
+ const menu = new FloatMenu({ width: 300, height: 400 });
321
+ menu.show();
322
+ });
323
+ ```
324
+
325
+ ### Dynamic UI Updates
326
+
327
+ ```typescript
328
+ // Update UI from JavaScript
329
+ setTimeout(() => {
330
+ menu.setComponentValue('mySwitch', true); // Turn switch on
331
+ const textComp = menu.getComponent<Text>('myText');
332
+ if (textComp) {
333
+ textComp.setText('Updated!');
334
+ }
335
+ }, 5000);
336
+ ```
337
+
338
+ ### New Components Demo
339
+
340
+ A comprehensive demo showcasing all new UI components is available in `demo-new-components.ts`:
341
+
342
+ ```bash
343
+ # Build the demo
344
+ npm run build:demo
345
+
346
+ # Run the demo with Frida
347
+ npm run frida:demo
348
+
349
+ # Or compile manually
350
+ frida-compile demo-new-components.ts -o demo-new-components-compiled.js -c
351
+ frida -U -f com.example.app -l demo-new-components-compiled.js
352
+ ```
353
+
354
+ The demo demonstrates:
355
+ - **Slider**: Range control with min/max/step constraints
356
+ - **Collapsible**: Expandable/collapsible panels with child components
357
+ - **Category**: Section headers for organizing UI
358
+ - **TextInput**: Single and multi-line text entry
359
+ - **NumberInput**: Numeric input with validation and constraints
360
+ - **Interaction**: Components communicating with each other
361
+
362
+ ## Project Structure
363
+
364
+ ```
365
+ frida-float-menu/
366
+ ├── src/ # Library source code
367
+ │ ├── index.ts # Main entry point (re-exports everything)
368
+ │ ├── event-emitter.ts # Event system
369
+ │ ├── logger.ts # Logging utilities
370
+ │ ├── ui-components.ts # UI component definitions (all components)
371
+ │ └── float-menu.ts # FloatMenu main class
372
+ ├── example.ts # TypeScript usage example (basic components)
373
+ ├── demo-new-components.ts # TypeScript demo for new components
374
+ ├── example.js # JavaScript usage example
375
+ ├── package.json # Package configuration
376
+ └── README.md # This file
377
+ ```
378
+
379
+ ## Building and Development
380
+
381
+ ### For library users
382
+ No build required - use the TypeScript source directly with frida-compile.
383
+
384
+ ### For library developers
385
+ ```bash
386
+ npm install # Install dependencies
387
+ npm run check # Type-check without emitting
388
+ npm run build-example # Build example script
389
+ ```
390
+
391
+ ## Limitations
392
+
393
+ - Requires Android API level 26+ for `TYPE_APPLICATION_OVERLAY`
394
+ - UI operations automatically scheduled on main thread
395
+ - Uses default Android widgets (no custom styling)
396
+ - Tested on Android only (not iOS)
397
+
398
+ ## License
399
+
400
+ MIT
401
+
402
+ ## Contributing
403
+
404
+ Contributions are welcome! Please submit issues and pull requests to enhance the library.
package/lib/api.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ export declare const API: {
2
+ readonly ImageView: Java.Wrapper<{}>;
3
+ readonly ImageViewScaleType: Java.Wrapper<{}>;
4
+ readonly FrameLayoutParams: Java.Wrapper<{}>;
5
+ readonly Gravity: Java.Wrapper<{}>;
6
+ readonly DialogMultiChoiceListener: Java.Wrapper<{}>;
7
+ readonly DialogClickListener: Java.Wrapper<{}>;
8
+ readonly HorizontalScrollView: Java.Wrapper<{}>;
9
+ readonly Context: Java.Wrapper<{}>;
10
+ readonly GradientDrawable: Java.Wrapper<{}>;
11
+ readonly BitmapFactory: Java.Wrapper<{}>;
12
+ readonly Base64: Java.Wrapper<{}>;
13
+ readonly Button: Java.Wrapper<{}>;
14
+ readonly Color: Java.Wrapper<{}>;
15
+ readonly ViewManager: Java.Wrapper<{}>;
16
+ readonly JString: Java.Wrapper<{}>;
17
+ readonly View: Java.Wrapper<{}>;
18
+ readonly GridLayout: Java.Wrapper<{}>;
19
+ readonly CheckBox: Java.Wrapper<{}>;
20
+ readonly SeekBar: Java.Wrapper<{}>;
21
+ readonly Html: Java.Wrapper<{}>;
22
+ readonly SeekBarOnSeekBarChangeListener: Java.Wrapper<{}>;
23
+ readonly AdapterViewOnItemSelectedListener: Java.Wrapper<{}>;
24
+ readonly Spinner: Java.Wrapper<{}>;
25
+ readonly ArrayAdapter: Java.Wrapper<{}>;
26
+ readonly R_layout: Java.Wrapper<{}>;
27
+ readonly DialogInterfaceOnClickListener: Java.Wrapper<{}>;
28
+ readonly AlertDialogBuilder: Java.Wrapper<{}>;
29
+ readonly AlertDialog: Java.Wrapper<{}>;
30
+ readonly OnTouchListener: Java.Wrapper<{}>;
31
+ readonly MotionEvent: Java.Wrapper<{}>;
32
+ readonly EditText: Java.Wrapper<{}>;
33
+ readonly Point: Java.Wrapper<{}>;
34
+ readonly DisplayMetrics: Java.Wrapper<{}>;
35
+ readonly TextViewBufferType: Java.Wrapper<{}>;
36
+ readonly InputType: Java.Wrapper<{}>;
37
+ readonly GridLayoutParams: Java.Wrapper<{}>;
38
+ readonly Switch: Java.Wrapper<{}>;
39
+ readonly OnCheckedChangeListener: Java.Wrapper<{}>;
40
+ readonly CompoundButtonOnCheckedChangeListener: Java.Wrapper<{}>;
41
+ readonly TextView: Java.Wrapper<{}>;
42
+ readonly OnClickListener: Java.Wrapper<{}>;
43
+ readonly FrameLayout: Java.Wrapper<{}>;
44
+ readonly ViewGroupLayoutParams: Java.Wrapper<{}>;
45
+ readonly LayoutParams: Java.Wrapper<{}>;
46
+ readonly BuildVERSION: Java.Wrapper<{}>;
47
+ readonly LinearLayout: Java.Wrapper<{}>;
48
+ readonly LinearLayoutParams: Java.Wrapper<{}>;
49
+ readonly ScrollView: Java.Wrapper<{}>;
50
+ };
package/lib/api.js ADDED
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.API = void 0;
4
+ exports.API = {
5
+ get ImageView() {
6
+ return Java.use("android.widget.ImageView");
7
+ },
8
+ get ImageViewScaleType() {
9
+ return Java.use("android.widget.ImageView$ScaleType");
10
+ },
11
+ get FrameLayoutParams() {
12
+ return Java.use("android.widget.FrameLayout$LayoutParams");
13
+ },
14
+ get Gravity() {
15
+ return Java.use("android.view.Gravity");
16
+ },
17
+ get DialogMultiChoiceListener() {
18
+ return Java.use("android.content.DialogInterface$OnMultiChoiceClickListener");
19
+ },
20
+ get DialogClickListener() {
21
+ return Java.use("android.content.DialogInterface$OnClickListener");
22
+ },
23
+ get HorizontalScrollView() {
24
+ return Java.use("android.widget.HorizontalScrollView");
25
+ },
26
+ get Context() {
27
+ return Java.use("android.content.Context");
28
+ },
29
+ get GradientDrawable() {
30
+ return Java.use("android.graphics.drawable.GradientDrawable");
31
+ },
32
+ get BitmapFactory() {
33
+ return Java.use("android.graphics.BitmapFactory");
34
+ },
35
+ get Base64() {
36
+ return Java.use("android.util.Base64");
37
+ },
38
+ get Button() {
39
+ return Java.use("android.widget.Button");
40
+ },
41
+ get Color() {
42
+ return Java.use("android.graphics.Color");
43
+ },
44
+ get ViewManager() {
45
+ return Java.use("android.view.ViewManager");
46
+ },
47
+ get JString() {
48
+ return Java.use("java.lang.String");
49
+ },
50
+ get View() {
51
+ return Java.use("android.view.View");
52
+ },
53
+ get GridLayout() {
54
+ return Java.use("android.widget.GridLayout");
55
+ },
56
+ get CheckBox() {
57
+ return Java.use("android.widget.CheckBox");
58
+ },
59
+ get SeekBar() {
60
+ return Java.use("android.widget.SeekBar");
61
+ },
62
+ get Html() {
63
+ return Java.use("android.text.Html");
64
+ },
65
+ get SeekBarOnSeekBarChangeListener() {
66
+ return Java.use("android.widget.SeekBar$OnSeekBarChangeListener");
67
+ },
68
+ get AdapterViewOnItemSelectedListener() {
69
+ return Java.use("android.widget.AdapterView$OnItemSelectedListener");
70
+ },
71
+ get Spinner() {
72
+ return Java.use("android.widget.Spinner");
73
+ },
74
+ get ArrayAdapter() {
75
+ return Java.use("android.widget.ArrayAdapter");
76
+ },
77
+ get R_layout() {
78
+ return Java.use("android.R$layout");
79
+ },
80
+ get DialogInterfaceOnClickListener() {
81
+ return Java.use("android.content.DialogInterface$OnClickListener");
82
+ },
83
+ get AlertDialogBuilder() {
84
+ return Java.use("android.app.AlertDialog$Builder");
85
+ },
86
+ get AlertDialog() {
87
+ return Java.use("android.app.AlertDialog");
88
+ },
89
+ get OnTouchListener() {
90
+ return Java.use("android.view.View$OnTouchListener");
91
+ },
92
+ get MotionEvent() {
93
+ return Java.use("android.view.MotionEvent");
94
+ },
95
+ get EditText() {
96
+ return Java.use("android.widget.EditText");
97
+ },
98
+ get Point() {
99
+ return Java.use("android.graphics.Point");
100
+ },
101
+ get DisplayMetrics() {
102
+ return Java.use("android.util.DisplayMetrics");
103
+ },
104
+ get TextViewBufferType() {
105
+ return Java.use("android.widget.TextView$BufferType");
106
+ },
107
+ get InputType() {
108
+ return Java.use("android.text.InputType");
109
+ },
110
+ get GridLayoutParams() {
111
+ return Java.use("android.widget.GridLayout$LayoutParams");
112
+ },
113
+ get Switch() {
114
+ return Java.use("android.widget.Switch");
115
+ },
116
+ get OnCheckedChangeListener() {
117
+ return Java.use("android.widget.CompoundButton$OnCheckedChangeListener");
118
+ },
119
+ get CompoundButtonOnCheckedChangeListener() {
120
+ return Java.use("android.widget.CompoundButton$OnCheckedChangeListener");
121
+ },
122
+ get TextView() {
123
+ return Java.use("android.widget.TextView");
124
+ },
125
+ get OnClickListener() {
126
+ return Java.use("android.view.View$OnClickListener");
127
+ },
128
+ get FrameLayout() {
129
+ return Java.use("android.widget.FrameLayout");
130
+ },
131
+ get ViewGroupLayoutParams() {
132
+ return Java.use("android.view.ViewGroup$LayoutParams");
133
+ },
134
+ get LayoutParams() {
135
+ return Java.use("android.view.WindowManager$LayoutParams");
136
+ },
137
+ get BuildVERSION() {
138
+ return Java.use("android.os.Build$VERSION");
139
+ },
140
+ get LinearLayout() {
141
+ return Java.use("android.widget.LinearLayout");
142
+ },
143
+ get LinearLayoutParams() {
144
+ return Java.use("android.widget.LinearLayout$LayoutParams");
145
+ },
146
+ get ScrollView() {
147
+ return Java.use("android.widget.ScrollView");
148
+ },
149
+ };
@@ -0,0 +1,11 @@
1
+ import { UIComponent } from "./ui-components";
2
+ export declare class Button extends UIComponent {
3
+ private label;
4
+ private handler;
5
+ private kind;
6
+ constructor(id: string, label: string, kind?: "primary" | "danger");
7
+ protected createView(context: any): void;
8
+ protected updateView(): void;
9
+ setLabel(label: string): void;
10
+ setOnClick(handler: () => void): void;
11
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Button = 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 Button extends ui_components_1.UIComponent {
8
+ constructor(id, label, kind = "primary") {
9
+ super(id);
10
+ this.handler = null;
11
+ this.kind = "primary";
12
+ this.label = label;
13
+ this.kind = kind;
14
+ this.value = null;
15
+ }
16
+ createView(context) {
17
+ const Button = api_1.API.Button;
18
+ this.view = Button.$new(context);
19
+ const String = api_1.API.JString;
20
+ this.view.setText(String.$new(this.label));
21
+ (0, style_1.applyStyle)(this.view, this.kind === "danger" ? "dangerButton" : "primaryButton", this.menu.options.theme);
22
+ const OnClickListener = api_1.API.OnClickListener;
23
+ const self = this;
24
+ const clickListener = Java.registerClass({
25
+ name: "com.frida.MyClickListener" +
26
+ Date.now() +
27
+ Math.random().toString(36).substring(6),
28
+ implements: [OnClickListener],
29
+ methods: {
30
+ onClick: function (v) {
31
+ self.emit("click");
32
+ if (self.handler) {
33
+ setImmediate(self.handler);
34
+ }
35
+ },
36
+ },
37
+ });
38
+ this.view.setOnClickListener(clickListener.$new());
39
+ }
40
+ updateView() {
41
+ }
42
+ setLabel(label) {
43
+ this.label = label;
44
+ if (!this.view) {
45
+ console.warn(`[Button:${this.id}] Cannot set label - view not initialized`);
46
+ return;
47
+ }
48
+ Java.scheduleOnMainThread(() => {
49
+ const String = api_1.API.JString;
50
+ this.view.setText(String.$new(label));
51
+ });
52
+ }
53
+ setOnClick(handler) {
54
+ this.handler = handler;
55
+ }
56
+ }
57
+ exports.Button = Button;
@@ -0,0 +1,8 @@
1
+ import { UIComponent } from "./ui-components";
2
+ export declare class Category extends UIComponent {
3
+ private label;
4
+ constructor(id: string, label: string);
5
+ protected createView(context: any): void;
6
+ protected updateView(): void;
7
+ setLabel(label: string): void;
8
+ }