Compare commits

...
Sign in to create a new pull request.

260 commits

Author SHA1 Message Date
OTKUSteyler
a707e6fd05
Update UpdaterModule.kt
Some checks failed
Build APK / Build and push (push) Failing after 6m51s
2026-09-12 15:55:10 +02:00
OTKUSteyler
d55ed5221c
Update LogBoxModule.kt 2026-09-12 12:52:36 +02:00
OTKUSteyler
a5af0bddb8
Update FontsModule.kt 2026-09-12 12:41:28 +02:00
OTKUSteyler
9611038048
Update FontsModule.kt 2026-09-12 12:33:34 +02:00
OTKUSteyler
06dde39cfd
Update LogBoxModule.kt 2026-09-12 12:25:15 +02:00
OTKUSteyler
69496c1f3c Revert "Fix: Add missing LogBoxModule and onActivity hook - fixes blank plugin/theme tabs"
This reverts commit 1a9fd61ec3.
2026-09-12 11:27:48 +02:00
OTKUSteyler
ce6f201fcd
Update FontsModule.kt 2026-09-12 10:13:49 +02:00
OTKUSteyler
73a93a29bb
Update Main.kt 2026-09-12 10:10:19 +02:00
OTKUSteyler
ee7e30e67c
Update FontsModule.kt 2026-09-12 10:08:55 +02:00
OTKUSteyler
57ebd3daed
Update LogBoxModule.kt 2026-09-11 22:12:32 +02:00
OTKUSteyler
82214b6ed0
Update FontsModule.kt 2026-09-11 21:48:46 +02:00
OTKUSteyler
2b9956d97b
Update LogBoxModule.kt 2026-09-10 17:47:17 +02:00
OTKUSteyler
b2c7e23a57
Update FontsModule.kt 2026-09-10 17:15:27 +02:00
OTKUSteyler
468311bbba
Update LogBoxModule.kt 2026-09-10 17:15:05 +02:00
OTKUSteyler
7f90a61ca5
Delete app/src/main/kotlin/GoonXposed/xposed/xposed/a 2026-09-10 16:58:53 +02:00
OTKUSteyler
17e1b9220f
Create a 2026-09-10 16:57:51 +02:00
OTKUSteyler
34b4a9f30c
Delete app/src/main/kotlin/GoonXposed/xposed/xposed/a 2026-09-10 16:56:10 +02:00
OTKUSteyler
abb1c6ddd8
Create a 2026-09-10 16:55:55 +02:00
OTKUSteyler
32421df002
Update Main.kt 2026-09-10 15:20:01 +02:00
OTKUSteyler
f16af054be
Update Utils.kt 2026-09-10 15:11:45 +02:00
OTKUSteyler
3a6abc9a79
Update FontsModule.kt 2026-09-10 13:54:51 +02:00
OTKUSteyler
a836fd1e73
Update FontsModule.kt 2026-09-10 12:49:20 +02:00
OTKUSteyler
0190e2d468
Update Main.kt 2026-09-10 12:18:30 +02:00
OTKUSteyler
ea21c20d18
Update Main.kt 2026-09-10 12:09:38 +02:00
OTKUSteyler
ad10c8a2a1
Update build.gradle.kts 2026-09-10 08:05:34 +02:00
OTKUSteyler
65d6ae239a
Update build.gradle.kts 2026-09-09 21:16:48 +02:00
OTKUSteyler
415f0066d7
Update build.gradle.kts 2026-09-09 21:13:44 +02:00
OTKUSteyler
4f3c599c3b
Update build.gradle.kts 2026-09-09 20:25:56 +02:00
OTKUSteyler
5e8e4538f8
Update build.gradle.kts 2026-09-09 20:17:37 +02:00
OTKUSteyler
64f83dcd5c
Update FontsModule.kt 2026-09-09 19:52:56 +02:00
OTKUSteyler
cd418c2d79
Update LogBoxActions.kt 2026-09-09 19:51:20 +02:00
OTKUSteyler
0267d095e2
Update FontsModule.kt 2026-09-09 19:42:01 +02:00
OTKUSteyler
2d62630e30
Update Main.kt 2026-09-09 17:45:20 +02:00
OTKUSteyler
750a4cd5b0
Update Main.kt 2026-09-05 20:37:19 +02:00
OTKUSteyler
baacefef54
Update FontsModule.kt 2026-09-05 19:46:48 +02:00
OTKUSteyler
f96d53db9a
Update Main.kt 2026-09-05 13:43:27 +02:00
OTKUSteyler
720e84487e
Update FontsModule.kt 2026-09-05 13:26:30 +02:00
OTKUSteyler
8616f04995
Update ThemesModule.kt 2026-09-05 13:25:51 +02:00
OTKUSteyler
7152b06265
Update Main.kt 2026-09-05 13:25:17 +02:00
OTKUSteyler
2b3510f55d
Update Utils.kt 2026-09-05 12:53:22 +02:00
OTKUSteyler
d1334d0ec0
Update FixResourcesModule.kt 2026-09-05 12:49:09 +02:00
OTKUSteyler
853564ebe9
Update FontsModule.kt 2026-09-05 12:48:11 +02:00
OTKUSteyler
3bf2f76c56
Update RecoveryMenu.kt 2026-09-05 12:47:19 +02:00
OTKUSteyler
6f707af677
Update OptionsMenu.kt 2026-09-05 12:45:27 +02:00
OTKUSteyler
1abaaff7d1
Update PayloadGlobalModule.kt 2026-09-05 12:44:49 +02:00
OTKUSteyler
3aa888bc26
Update HookScriptLoaderModule.kt 2026-09-05 12:44:22 +02:00
OTKUSteyler
d57081364b
Update SysColorsModule.kt 2026-09-05 12:43:35 +02:00
OTKUSteyler
4599c2d96f
Update Utils.kt 2026-09-05 12:43:04 +02:00
OTKUSteyler
14a8067aea
Update Module.kt 2026-09-05 12:42:17 +02:00
OTKUSteyler
d719e15cf8
Add files via upload 2026-09-05 12:25:16 +02:00
OTKUSteyler
7814cd0e82
Add files via upload 2026-09-05 12:24:51 +02:00
OTKUSteyler
469cdfb95e
Add files via upload 2026-09-05 12:24:24 +02:00
OTKUSteyler
e90c20bfc5
Add files via upload 2026-09-05 12:23:41 +02:00
OTKUSteyler
fc9dd1ee9b
Add files via upload 2026-09-05 12:22:25 +02:00
OTKUSteyler
c85761f92e
Add files via upload 2026-09-05 12:21:42 +02:00
OTKUSteyler
c342b478c1
Update gradle.properties 2026-09-05 12:16:21 +02:00
OTKUSteyler
fc6772a124
Update gradle.properties 2026-09-05 12:13:46 +02:00
OTKUSteyler
743b6283c0
Update build.gradle.kts 2026-09-04 06:25:39 +02:00
OTKUSteyler
3562b0e730
Update FontsModule.kt 2026-09-03 21:06:47 +02:00
OTKUSteyler
26a356a158
Update xposed_init 2026-09-03 20:15:40 +02:00
OTKUSteyler
a3ebf0259e
Update xposed_init 2026-09-03 20:12:29 +02:00
OTKUSteyler
df097bfc81
Update build.gradle.kts 2026-09-03 19:35:10 +02:00
OTKUSteyler
765c546c20
Update Module.kt 2026-09-03 18:29:43 +02:00
OTKUSteyler
13bdcdad03
Update FontsModule.kt 2026-09-03 18:27:03 +02:00
OTKUSteyler
b083a66afd
Update FontsModule.kt
Some checks failed
Build APK / Build and push (push) Failing after 3m49s
2026-09-03 17:45:01 +02:00
OTKUSteyler
4115c3d4df
Update build.gradle.kts
Some checks failed
Build APK / Build and push (push) Failing after 3m58s
2026-09-03 15:36:30 +02:00
OTKUSteyler
c63eaa5a12
Update FontsModule.kt 2026-09-03 14:58:44 +02:00
OTKUSteyler
531cb9281c
Update FontsModule.kt 2026-09-03 13:00:51 +02:00
OTKUSteyler
bff796d574
Update FontsModule.kt 2026-09-03 12:45:07 +02:00
OTKUSteyler
f7d1b2ea1d
Update FontsModule.kt 2026-09-03 05:58:15 +02:00
OTKUSteyler
9a620545b4
Update FontsModule.kt 2026-09-02 16:17:06 +02:00
OTKUSteyler
6e7f5302e3
Update build.gradle.kts
Some checks failed
Build APK / Build and push (push) Failing after 4m49s
2026-09-02 15:27:31 +02:00
OTKUSteyler
ec787e7cf5
Update build.gradle.kts 2026-09-02 15:27:08 +02:00
OTKUSteyler
8ef48f3608
Update FontsModule.kt 2026-09-02 14:43:48 +02:00
OTKUSteyler
2bddedb96c
Update FontsModule.kt 2026-09-02 14:41:44 +02:00
OTKUSteyler
5d39748a28 Fix overload resolution ambiguity by replacing wildcard import with specific LogBoxModule import 2026-08-26 16:46:01 +02:00
OTKUSteyler
1a9fd61ec3 Fix: Add missing LogBoxModule and onActivity hook - fixes blank plugin/theme tabs 2026-08-26 16:41:59 +02:00
OTKUSteyler
a9a1dc4ad3 chore: Bump version to 1.3.6 2026-08-26 16:29:21 +02:00
OTKUSteyler
aab9fdc101 Fix: Add @Deprecated annotation to buildPayload override 2026-08-26 16:22:22 +02:00
OTKUSteyler
21029f5f72 Fix: Add @Deprecated annotation to buildPayload override 2026-08-26 16:22:10 +02:00
OTKUSteyler
64ffdf4f32 Fix: Add @Deprecated annotation to buildPayload override 2026-08-26 16:21:48 +02:00
OTKUSteyler
68c85dd812 Fix: Skip release signing when keystore not found and suppress deprecated warnings 2026-08-26 16:21:40 +02:00
OTKUSteyler
fd84dd0320 Fix: Remove invalid method parameters from UpdaterModule calls
- Line 86: Remove `isCustomUrlEnabled` reference (doesn't exist in UpdaterModule)
- Line 92: Remove `showUpdateDialog = false` parameter from `downloadScript()` call
- Line 96: Remove `showUpdateDialog = true` parameter from `downloadScript()` call

The `UpdaterModule.downloadScript()` method only accepts an optional `activity` parameter, not `showUpdateDialog`.
The logic has been simplified to check only if the main script exists.
2026-08-26 16:15:12 +02:00
OTKUSteyler
7df631b799
Update README.md 2026-08-26 16:09:02 +02:00
OTKUSteyler
3d45a8d70f
Merge branch 'kmmiio99o:master' into master 2026-08-26 16:05:36 +02:00
OTKUSteyler
2978e3b8d1
Merge branch 'kmmiio99o:master' into master 2026-08-26 06:16:01 +02:00
OTKUSteyler
ffcc29796c
Update LogBoxModule.kt 2026-08-18 10:38:53 +02:00
OTKUSteyler
79298ddf6c
Update LogBoxMenu.kt 2026-08-18 10:37:38 +02:00
OTKUSteyler
e0917110e1
Update LogBoxModule.kt 2026-08-18 10:29:36 +02:00
OTKUSteyler
1de8af79f0
Rename package from ShiggyXposed to GoonXposed 2026-08-18 10:20:54 +02:00
OTKUSteyler
5fe307a852
Update and rename Module.kt.txt to Module.kt 2026-08-18 10:19:28 +02:00
OTKUSteyler
08bfa8199d
Add files via upload 2026-08-18 10:18:42 +02:00
OTKUSteyler
2c94757947
Update CacheModule.kt 2026-08-18 10:09:31 +02:00
OTKUSteyler
85837531de
Delete app/src/main/kotlin/GoonXposed/xposed/xposed directory 2026-08-17 09:07:40 +02:00
OTKUSteyler
3360ee33f1
Rename Module.kt to GoonXposed directory 2026-08-17 09:07:18 +02:00
OTKUSteyler
d882007611
Delete app/src/main/kotlin/GoonXposed/xposed/xposed/Utils.kt 2026-08-17 09:06:16 +02:00
OTKUSteyler
bd9116e1cf
Rename Utils.kt to Utils.kt 2026-08-17 09:05:44 +02:00
OTKUSteyler
5e54c7bf61
Update LogBoxModule.kt 2026-08-17 08:58:41 +02:00
OTKUSteyler
bf6f3c0691
Refactor LogBoxModule to use urlEnabled instead of isEnabled 2026-08-17 08:45:26 +02:00
OTKUSteyler
7eb893bcc9
Update build.gradle.kts 2026-08-17 08:35:12 +02:00
OTKUSteyler
52f05764f4 Merge remote-tracking branch 'upstream/master' 2026-08-17 08:25:42 +02:00
OTKUSteyler
cdbbb3a957
Update README.md 2026-05-22 21:51:39 +02:00
OTKUSteyler
457af73f88
Update OptionsMenu.kt 2026-05-18 01:10:23 +02:00
OTKUSteyler
6be3d89176
Update LogBoxUtils.kt 2026-05-18 01:10:02 +02:00
OTKUSteyler
9267cb3918
Update LogBoxTheme.kt 2026-05-18 01:09:28 +02:00
OTKUSteyler
f55d1a4a62
Rename package from ShiggyXposed to GoonXposed 2026-05-18 01:09:06 +02:00
OTKUSteyler
cc0ffe6fb2
Update LogBoxMenu.kt 2026-05-18 01:08:46 +02:00
OTKUSteyler
acca6bfe47
Rename package from ShiggyXposed to GoonXposed 2026-05-18 01:08:09 +02:00
OTKUSteyler
8148f860e5
Update LogBoxConstants.kt 2026-05-18 01:07:46 +02:00
OTKUSteyler
f0e9503354
Update LogBoxComponents.kt 2026-05-18 01:07:24 +02:00
OTKUSteyler
4f779c9af0
Update RecoveryMenu.kt 2026-05-18 01:07:00 +02:00
OTKUSteyler
202152bbf0
Update LogBoxActions.kt 2026-05-18 01:05:58 +02:00
OTKUSteyler
d55b9dcda0
Rename package from ShiggyXposed to GoonXposed 2026-05-18 01:05:28 +02:00
OTKUSteyler
6f6f2e4abc
Update CustomBundleDialog.kt 2026-05-18 01:05:06 +02:00
OTKUSteyler
c3c21a26e0 Merge remote-tracking branch 'upstream/master' 2026-05-18 01:01:03 +02:00
OTKUSteyler
5e2fd369fe Merge remote-tracking branch 'upstream/master' 2026-02-14 21:00:53 +01:00
OTKUSteyler
7635ac1d90
Merge branch 'kmmiio99o:master' into master 2026-01-10 16:32:15 +00:00
OTKUSteyler
5769fe2211
Update CacheModule.kt 2026-01-03 00:24:07 +00:00
OTKUSteyler
04a799e7f6
Update BridgeModule.kt 2026-01-03 00:23:02 +00:00
OTKUSteyler
ed8d5fb7a8
Update BridgeModule.kt 2026-01-03 00:06:52 +00:00
OTKUSteyler
8038be3023
Update gradle.properties 2026-01-03 00:05:33 +00:00
OTKUSteyler
511fd1df4e
Update PerfPatchesModule.kt 2026-01-03 00:01:21 +00:00
OTKUSteyler
0b63dbbc9a
Update CacheModule.kt 2026-01-02 23:58:25 +00:00
OTKUSteyler
85290a619e Merge remote-tracking branch 'upstream/master' 2026-01-03 00:53:48 +01:00
OTKUSteyler
d1796e4c68 Merge remote-tracking branch 'upstream/master' 2025-12-11 18:29:19 +01:00
OTKUSteyler
f92e36e7d4
Merge branch 'kmmiio99o:master' into master 2025-12-10 07:01:53 +01:00
OTKUSteyler
cbf96e8b45
Update README.md 2025-12-07 23:38:33 +01:00
OTKUSteyler
4537e7d56c
Update README.md 2025-12-07 23:37:35 +01:00
OTKUSteyler
782c40b5d3
Merge branch 'kmmiio99o:master' into master 2025-12-07 23:36:03 +01:00
OTKUSteyler
21effc7f21
Update build.gradle.kts
Some checks failed
Build APK / Build and push (push) Failing after 4m47s
2025-11-30 22:47:37 +01:00
OTKUSteyler
cc1f7fe682
Update LogBoxModule.kt 2025-11-30 22:30:33 +01:00
OTKUSteyler
f619b8702c
Update build.gradle.kts 2025-11-29 11:58:34 +01:00
OTKUSteyler
b4c17583b6
Update Utils.kt 2025-11-28 21:46:14 +01:00
OTKUSteyler
ff308a190c
Update LogBoxModule.kt 2025-11-28 18:54:02 +01:00
OTKUSteyler
c5f3b83cdf
Update build.gradle.kts 2025-11-28 18:45:48 +01:00
OTKUSteyler
03c81d8cc9
Merge branch 'kmmiio99o:master' into master 2025-11-28 18:37:39 +01:00
OTKUSteyler
3c4c9ca555
Update build.yml 2025-11-28 18:33:04 +01:00
OTKUSteyler
19bade53a0 Merge remote-tracking branch 'upstream/master' 2025-11-28 18:28:20 +01:00
OTKUSteyler
351086110c
Lower minSdk and targetSdk to 28 2025-11-28 17:55:38 +01:00
OTKUSteyler
5bc83206b2
Update build.gradle.kts 2025-11-28 16:05:08 +01:00
OTKUSteyler
8aa226d6ca
Update versionCode and versionName to 1.3.2
Some checks failed
Build APK / Build and push (push) Failing after 4m40s
2025-11-28 15:53:59 +01:00
OTKUSteyler
02310df32f
Update LogBoxModule.kt 2025-11-28 15:53:26 +01:00
OTKUSteyler
ffdd65f74d
Update Utils.kt 2025-11-28 12:26:02 +01:00
OTKUSteyler
90b346b75a
Update build.gradle.kts 2025-11-28 11:56:47 +01:00
OTKUSteyler
3619dafd47
Update build.gradle.kts 2025-11-28 11:42:28 +01:00
OTKUSteyler
12491b2235
Update build.gradle.kts 2025-11-28 11:37:47 +01:00
OTKUSteyler
2dd8151138
Update build.gradle.kts 2025-11-28 11:13:01 +01:00
OTKUSteyler
8c033fe878
Update AndroidManifest.xml 2025-11-28 09:57:37 +01:00
OTKUSteyler
f6d2384fa5
Update AndroidManifest.xml 2025-11-28 09:53:05 +01:00
OTKUSteyler
2621359a61
Update AndroidManifest.xml 2025-11-28 09:45:37 +01:00
OTKUSteyler
9f8c521659
Update build.yml 2025-11-26 18:47:57 +01:00
OTKUSteyler
2ffe2f510d
Update build.yml 2025-11-26 18:35:10 +01:00
OTKUSteyler
f4d48fdf90
Delete .github/workflows/release.yml 2025-11-26 18:33:59 +01:00
OTKUSteyler
66bb7fce6a
Update build.yml 2025-11-26 17:27:56 +01:00
OTKUSteyler
42636b29e8
Update build.yml 2025-11-26 16:30:37 +01:00
OTKUSteyler
e0cb50aaea
Update build.yml 2025-11-26 16:24:32 +01:00
OTKUSteyler
f2371d1c7e
Update build.gradle.kts 2025-11-24 17:59:36 +01:00
OTKUSteyler
01f52c1e2f
Delete app/app directory 2025-11-24 17:52:21 +01:00
OTKUSteyler
8d1d6303d3
Add files via upload 2025-11-24 17:50:15 +01:00
OTKUSteyler
bf05c67966
Delete app/src/main/kotlin/GoonXposed/a 2025-11-24 17:48:25 +01:00
OTKUSteyler
4102b2298d
Create a 2025-11-24 17:48:14 +01:00
OTKUSteyler
2171fc59eb
Delete app/src/main/kotlin/io/github/revenge/xposed directory 2025-11-24 17:38:08 +01:00
OTKUSteyler
8389d19545
Add files via upload 2025-11-24 17:37:47 +01:00
OTKUSteyler
5fe672884e
Delete app/src/main/kotlin/ShiggyXposed/xposed/xposed directory 2025-11-24 17:29:20 +01:00
OTKUSteyler
9481d80e5f Update build.gradle.kts 2025-11-24 17:14:07 +01:00
OTKUSteyler
3f309f58bb
Update UpdaterModule.kt 2025-11-24 16:58:04 +01:00
OTKUSteyler
004bba80ae
Update UpdaterModule.kt 2025-11-24 16:57:36 +01:00
OTKUSteyler
0fc969cf00
Update BridgeModule.kt 2025-11-24 16:21:39 +01:00
OTKUSteyler
691db71d12
Update recovery alert title from ShiggyCord to GoonCord 2025-11-23 18:50:47 +01:00
OTKUSteyler
07265446cf
Update ThemesModule.kt 2025-11-23 18:46:38 +01:00
OTKUSteyler
86c9658318
Update SysColorsModule.kt 2025-11-23 18:46:07 +01:00
OTKUSteyler
8c584d7cfc
Update FontsModule.kt 2025-11-23 18:45:44 +01:00
OTKUSteyler
f42f53b375
Rename package from ShiggyXposed to GoonXposed 2025-11-23 18:45:03 +01:00
OTKUSteyler
8c6c43429d
Update BridgeModule.kt 2025-11-23 18:44:06 +01:00
OTKUSteyler
a4c6e4871e
Update BlockCrashReportingModule.kt 2025-11-23 18:42:57 +01:00
OTKUSteyler
f17cdc8fd0
Update BlockDeepLinksTrackingModule.kt 2025-11-23 18:42:29 +01:00
OTKUSteyler
3506cfc97d
Update CacheModule.kt 2025-11-23 18:41:56 +01:00
OTKUSteyler
7d8a71eaf6
Update FixResourcesModule.kt 2025-11-23 18:41:18 +01:00
OTKUSteyler
eeac21e2aa
Update HookScriptLoaderModule.kt 2025-11-23 18:40:46 +01:00
OTKUSteyler
eb58fdfa00
Update LogBoxModule.kt 2025-11-23 18:39:46 +01:00
OTKUSteyler
44288a202d
Update Constants.kt 2025-11-23 18:38:22 +01:00
OTKUSteyler
3196f8a0a4
Update PayloadGlobalModule.kt 2025-11-23 18:11:04 +01:00
OTKUSteyler
63c12c7984
Change package name in PluginsModule.kt
Updated package name from ShiggyXposed to GoonXposed.
2025-11-23 18:10:01 +01:00
OTKUSteyler
9a716efd37
Update Utils.kt 2025-11-23 18:09:07 +01:00
OTKUSteyler
136b6f7c46
Update Main.kt 2025-11-23 18:08:30 +01:00
OTKUSteyler
63d8e86725
Update UpdaterModule.kt 2025-11-23 16:42:24 +01:00
OTKUSteyler
6cfb92faf1
Update UpdaterModule.kt 2025-11-23 16:39:40 +01:00
OTKUSteyler
f47d6d1d93 Merge remote-tracking branch 'upstream/master' 2025-11-22 22:04:25 +01:00
OTKUSteyler
2eb7cbf84e
Update LogBoxModule.kt 2025-11-22 00:30:46 +01:00
OTKUSteyler
3d6f61bb56
Update FontsModule.kt 2025-11-22 00:26:34 +01:00
OTKUSteyler
01fdbe19d7
Update UpdaterModule.kt 2025-11-22 00:23:41 +01:00
OTKUSteyler
4ecfdfce27
Update Main.kt 2025-11-22 00:18:09 +01:00
OTKUSteyler
e198c43ce2
Update ThemesModule.kt 2025-11-22 00:13:17 +01:00
OTKUSteyler
ee7c27d280
Update SysColorsModule.kt 2025-11-22 00:12:52 +01:00
OTKUSteyler
9a6886ad71
Update FontsModule.kt 2025-11-22 00:12:24 +01:00
OTKUSteyler
019075d927
Update LogBoxModule.kt 2025-11-22 00:11:39 +01:00
OTKUSteyler
6131c74016
Update PayloadGlobalModule.kt 2025-11-22 00:10:53 +01:00
OTKUSteyler
52e10aca4c
Update PluginsModule.kt 2025-11-22 00:10:35 +01:00
OTKUSteyler
4b7192edfa
Update AdditionalBridgeMethodsModule.kt 2025-11-22 00:09:44 +01:00
OTKUSteyler
ac5d0e551b
Update BridgeModule.kt 2025-11-22 00:09:14 +01:00
OTKUSteyler
d04d1d608d
Update BlockCrashReportingModule.kt 2025-11-22 00:08:32 +01:00
OTKUSteyler
46e37bfe7e
Update BlockDeepLinksTrackingModule.kt 2025-11-22 00:07:56 +01:00
OTKUSteyler
e9a2a8c51e
Update CacheModule.kt 2025-11-22 00:07:28 +01:00
OTKUSteyler
e453be092b
Update FixResourcesModule.kt 2025-11-22 00:06:49 +01:00
OTKUSteyler
ced4d26d20
Update FixResourcesModule.kt 2025-11-22 00:06:40 +01:00
OTKUSteyler
683137451b
Update HookScriptLoaderModule.kt 2025-11-22 00:06:17 +01:00
OTKUSteyler
61af37117d
Update LogBoxModule.kt 2025-11-22 00:05:06 +01:00
OTKUSteyler
fb8a6119f9
Update PayloadGlobalModule.kt 2025-11-22 00:03:52 +01:00
OTKUSteyler
62513e7a04
Update UpdaterModule.kt 2025-11-22 00:02:59 +01:00
OTKUSteyler
007a6f8a59
Add files via upload 2025-11-21 23:54:09 +01:00
OTKUSteyler
aa0970913c
Update PayloadGlobalModule.kt 2025-11-21 23:48:46 +01:00
OTKUSteyler
4ae471a7b9
Update Main.kt 2025-11-21 23:47:28 +01:00
OTKUSteyler
f19d654e87
Update build.gradle.kts 2025-11-21 23:45:51 +01:00
OTKUSteyler
7348da9aff
Update LogBoxModule.kt
Some checks failed
Build APK / Build and push (push) Failing after 4m44s
2025-11-19 21:50:01 +01:00
OTKUSteyler
9a6d328b47
Update build.gradle.kts 2025-11-19 21:45:50 +01:00
OTKUSteyler
afdda092bc
Update build.gradle.kts 2025-11-10 23:57:59 +01:00
OTKUSteyler
6858113d54
Update build.gradle.kts
Some checks failed
Build APK / Build and push (push) Failing after 4m41s
2025-11-10 23:38:54 +01:00
OTKUSteyler
adeba43dca
Update AndroidManifest.xml
Some checks failed
Build APK / Build and push (push) Failing after 4m38s
2025-11-09 11:14:52 +01:00
OTKUSteyler
660ee94361
Update build.yml
Some checks failed
Build APK / Build and push (push) Failing after 7m3s
2025-11-06 23:26:36 +01:00
OTKUSteyler
ae7ab4fd21
Update AndroidManifest.xml 2025-11-06 23:20:27 +01:00
OTKUSteyler
cf531f247a
Merge pull request #3 from kmmiio99o/master
Update ThemesModule.kt
2025-11-06 23:10:21 +01:00
kmmiio99o
c1e73bc602
Update ThemesModule.kt 2025-11-06 23:06:47 +01:00
OTKUSteyler
ccd0a1f066
Update ThemesModule.kt 2025-11-06 22:58:27 +01:00
OTKUSteyler
f210de66f2
Merge pull request #1 from kmmiio99o/patch-1
Updated ThemesModule.kt
2025-11-06 22:41:04 +01:00
kmmiio99o
1d0c42680f
Update ThemesModule.kt 2025-11-06 22:39:07 +01:00
OTKUSteyler
6e58a231e0
Update Main.kt 2025-11-06 22:34:46 +01:00
OTKUSteyler
4d94dccdfc
Update ThemesModule.kt 2025-11-06 22:34:25 +01:00
OTKUSteyler
4ab61ffcc5
Update Main.kt 2025-11-06 22:33:45 +01:00
OTKUSteyler
5eede3f588
Update Main.kt 2025-11-06 22:28:42 +01:00
OTKUSteyler
28d9fbabc8
Update Main.kt 2025-11-06 22:19:06 +01:00
OTKUSteyler
651e647f29
Update ThemesModule.kt 2025-11-06 22:10:15 +01:00
OTKUSteyler
0a712869d5
Update Main.kt 2025-11-06 22:00:56 +01:00
OTKUSteyler
3d4e9d052b
Update build.yml 2025-11-06 21:43:57 +01:00
OTKUSteyler
a05d9a9b38
Update LogBoxModule.kt 2025-11-06 16:01:06 +01:00
OTKUSteyler
d0160e829f
Update Main.kt 2025-11-06 15:53:54 +01:00
OTKUSteyler
fb8756b371
Update LogBoxModule.kt 2025-11-06 15:21:26 +01:00
OTKUSteyler
2ddfdd3bfa
Update Constants.kt 2025-11-06 15:13:31 +01:00
OTKUSteyler
078604ef25
Update BridgeModule.kt 2025-11-06 13:57:35 +01:00
OTKUSteyler
0bacc54ac4
Update AdditionalBridgeMethodsModule.kt 2025-11-05 23:17:26 +01:00
OTKUSteyler
af9bd39358
Update BridgeModule.kt 2025-11-05 23:16:29 +01:00
OTKUSteyler
67317dde13
Update FontsModule.kt 2025-11-05 23:15:34 +01:00
OTKUSteyler
eccadcdeff
Update SysColorsModule.kt 2025-11-05 23:14:36 +01:00
OTKUSteyler
a854f81dda
Update ThemesModule.kt 2025-11-05 23:14:02 +01:00
OTKUSteyler
eeec556c9f
Update FixResourcesModule.kt 2025-11-05 23:12:47 +01:00
OTKUSteyler
48d1cd7807
Update HookScriptLoaderModule.kt 2025-11-05 23:11:28 +01:00
OTKUSteyler
be25ad7213
Update LogBoxModule.kt 2025-11-05 23:10:08 +01:00
OTKUSteyler
7a90e92892
Update PayloadGlobalModule.kt 2025-11-05 23:07:49 +01:00
OTKUSteyler
c06ab2754d
Update UpdaterModule.kt 2025-11-05 23:06:54 +01:00
OTKUSteyler
02d6302a8c
Update Utils.kt 2025-11-05 23:05:42 +01:00
OTKUSteyler
76f8a3cd01
Update Module.kt 2025-11-05 23:05:00 +01:00
OTKUSteyler
3905a1327d
Update Constants.kt 2025-11-05 23:04:31 +01:00
OTKUSteyler
63892f2a8f
Update Main.kt 2025-11-05 23:03:54 +01:00
OTKUSteyler
62336a53a9
Update AndroidManifest.xml 2025-11-05 22:53:14 +01:00
OTKUSteyler
052edd13fa
Merge branch 'ShiggyCord-Team:master' into master 2025-11-05 22:48:10 +01:00
OTKUSteyler
f9e29656fa
Update build.yml 2025-11-05 20:07:22 +01:00
OTKUSteyler
f035c217e6
Update UpdaterModule.kt 2025-11-03 22:42:24 +01:00
OTKUSteyler
c4734b8b90
Update strings.xml 2025-11-03 22:21:30 +01:00
OTKUSteyler
50994e9278
Rename project from ShiggyXposed to GoonXposed 2025-10-22 23:46:10 +02:00
OTKUSteyler
ed704eb7f8
Rename application and namespace to GoonXposed 2025-10-22 23:45:42 +02:00
OTKUSteyler
f195d82414
Update xposed_init 2025-10-22 23:44:36 +02:00
39 changed files with 1611 additions and 663 deletions

2
.idea/.name generated
View file

@ -1 +1 @@
ShiggyXposed GoonXposed

205
README.md
View file

@ -1,191 +1,40 @@
# ShiggyXposed # GoonXposed
ShiggyXposed is an Xposed module (Kotlin) that injects the ShiggyCord client modifications into the official Discord Android application. It provides an in-app recovery/dev menu (LogBox) that lets you manage bundle loading, themes, and other developer helpers. GoonXposed is a root Xposed module that injects the GoonCord Discord mobile client modifications into the official Discord application.
This README explains prerequisites, installation, usage, troubleshooting, and credits. If you want help, open an issue on the repository or join the project's support server (links below). ## Info
* Injects GoonCord client into the Discord mobile app.
--- * Built in Kotlin.
* Material 3 like Shake menu with some discord popup accents
## Table of Contents
- [What is this](#what-is-this)
- [Features](#features)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Using the Module](#using-the-module)
- [Recovery / Options / Themes menu](#recovery--options--themes-menu)
- [Bundle injection / Custom bundle URL](#bundle-injection--custom-bundle-url)
- [Development / Building](#development--building)
- [Troubleshooting & FAQ](#troubleshooting--faq)
- [Contributing](#contributing)
- [Credits](#credits)
- [License](#license)
- [Contact & Links](#contact--links)
---
## What is this
ShiggyXposed injects a patched ShiggyCord bundle into the official Discord application by using the Xposed framework. It's intended for users who run a rooted Android device and want to apply client-side modifications to Discord.
---
## Features
- Inject a custom ShiggyCord bundle into Discord.
- Toggle bundle injection on/off (marker-based).
- Load a custom bundle URL and toggle it on/off.
- Recovery/LogBox action sheet for reload, safe-mode, refetch/reset, and options.
- Options to change the LogBox menu appearance (System / Light / Dark) and a set of menu color "flavors".
- In-place UI theming for the recovery/options menus.
- Helpers for refetching or backing up the currently loaded bundle.
---
## Prerequisites ## Prerequisites
To use this module, your device must meet the following requirements:
Before installing and using ShiggyXposed: * **Root Access**: Provided by Magisk, KernelSU, KernelSUNext, or Sukisu Ultra.
* **Xposed Framework**: Use JingMatrix Fork of [LSPosed](https://github.com/JingMatrix/LSPosed).
- A rooted Android device. Supported root solutions you might use: * **Target Application**: An official Discord application (stable, beta, or alpha version).
- Magisk, KernelSU, KernelSUNext, or Sukisu Ultra.
- Xposed framework installed. The project targets LSPosed or forks because of compatibility with modern Android and Discord:
- Recommended: JingMatrix Fork of [LSPosed](https://github.com/JingMatrix/LSPosed)
- The official Discord Android application (stable/beta/alpha) installed and included in the module scope.
---
## Installation ## Installation
1. Download the latest version of the module from the [Releases](https://github.com/OTKUSteyler/GoonXposed/releases) page.
2. Install the downloaded APK file on your device.
3. Open the LSPosed manager application.
4. Go to the **Modules** section and enable **GoonXposed**.
5. In the module's settings, set the scope to include the **Discord** application.
6. Reboot your device for the changes to take effect.
1. Download the latest APK from the repository Releases: The project is built with Kotlin and inherits its foundational structure from KettuXposed.
- https://github.com/kmmiio99o/ShiggyXposed/releases
2. Install the APK on your device (standard package install).
3. Open your LSPosed manager (or chosen Xposed manager).
4. Enable the ShiggyXposed module and ensure the module's scope includes the Discord app.
5. Reboot your device (or restart the system process) for changes to take effect.
--- # Troubleshooting
## Using the Module - Module not working: Ensure the module is enabled in LSPosed and that Discord is correctly selected in its scope. if still nothing, head to our [discord support server](https://discord.gg/nQykFF9Ud6)
- Any other issues: Same server as above, listing them all is not worth it.
Once installed and active, you can open the bundled Recovery/LogBox menu (depending on the hooked RN dev dialog) to access all tools. # Thanks & Credits
Recovery → Options → Themes: This project was made possible thanks to the work of:
- Recovery (Action Sheet) includes:
- Safe Mode toggle (toggle persisted safe-mode setting + optional theme handling)
- Load Custom Bundle
- Reload App
- Options (opens the Options action sheet)
- Options includes:
- Themes (open appearance/flavor controls)
- Toggle bundle injection (rename/add marker file in cache to prevent injection)
- Refetch Bundle (moves or resets current bundle and triggers a reload)
- Clear Cache & Reset (clears cached bundle and resets loader config)
- Back (return to Recovery)
Themes: · The LSPosed Team for the framework.
- Pick appearance: System / Light / Dark · JingMatrix for their LSPosed fork.
- Choose Menu Color Flavor: blue, green, mocha, vanilla, purple, amber, teal · [cocobo1](https://codeberg.org/cocobo1) for adjusting the Xposed module for Kettu client mod.
- Theme & flavor settings persist under the app's files directory (`files/logbox/LOGBOX_SETTINGS` and `files/logbox/LOGBOX_THEMES`) · [Revenge Team](https://github.com/revenge-mod) for making a really good Xposed Module to base of
Bundle injection: ![OTKUSteyler](https://count.getloli.com/@OTKUSteyler?name=OTKUSteyler&theme=miku&padding=7&offset=0&align=top&scale=1&pixelated=1&darkmode=1)
- When you disable injection, the module will create/rename a marker file in the cache directory so other components (loader) skip injection.
- Toggling injection is handled by `toggleBundleInjection(context)` and is persisted to `LOGBOX_SETTINGS`.
Custom bundle URL:
- The custom bundle loader configuration is stored in `files/pyoncord/loader.json`.
- You can enable/disable the custom URL and provide a remote URL (the module exposes a dialog for this).
---
## Development / Building
If you want to build the project locally:
- Prerequisites: JDK, Android SDK, and Gradle (the project uses the Gradle wrapper).
- From the repository root:
- Build debug APK:
```
./gradlew :app:assembleDebug
```
- Install to connected device (adb required):
```
adb install -r app/build/outputs/apk/debug/app-debug.apk
```
- Run and test on a rooted device/emulator with Xposed/LSPosed installed and Discord in scope.
Notes:
- The project is written in Kotlin and uses Android UI primitives to construct the recovery/LogBox UI. The dev menu is created in-place to avoid modifying Discord views.
---
## Troubleshooting & FAQ
1. Module not working or not showing in Discord?
- Ensure ShiggyXposed is enabled in LSPosed and Discord is included in the module's scope.
- Reboot after enabling the module.
- Confirm you have the compatible LSPosed fork installed (JingMatrix recommended).
2. Recovery menu shows visual glitches when changing themes?
- The menu attempts to apply colors in-place. If you see transient visual artifacts, try closing and reopening the menu — the settings are persisted and will apply on reopen.
- If an area does not update, please report which dialog/control (and the device/Android version) so it can be targeted.
3. Bundle injection not toggling?
- Toggling injection manipulates files under the app's cache directory. If that fails, check file permissions or whether the cache path changed on your build of Discord.
- You can also manually inspect `data/data/<discord.package>/cache/...` to see `.disabled` marker files (depending on your device and build).
4. I accidentally broke Discord — how do I recover?
- Use the Recovery → Options → Clear Cache & Reset option to remove cached bundles and restore default loader settings, then reload Discord.
- If Discord fails to start, reboot the device to make sure changes are applied cleanly.
If you still have issues, open an issue on GitHub or join the support server (link below). Please include:
- Device model and Android version
- Discord app version
- A clear description of the problem and steps to reproduce
- Any relevant logs or screenshots (redact personal data)
---
## Contributing
Contributions are welcome. If you want to help:
- Open an issue to discuss a bug or feature.
- Send pull requests with focused, well-documented changes.
- When working on UI or theme changes, test on multiple screen sizes and Android versions if possible.
Guidelines:
- Keep commits small and descriptive.
- Include code comments for complex logic (hooks, file-system operations).
- Respect user privacy — do not add telemetry or data exfiltration.
---
## Credits
This project stands on the shoulders of many open-source projects and contributors:
- [LSPosed Team](https://github.com/LSPosed) — the Xposed framework implementation used to run modules.
- [JingMatrix](https://github.com/JingMatrix) — author of the LSPosed fork referenced by many users.
- [cocobo1](https://codeberg.org/cocobo1) — for adapting some features to Xposed which [Revenge Team](https://github.com/revenge-mod) didn't.
- [Revenge Team](https://github.com/revenge-mod) — provided earlier Xposed module work that informed parts of this project.
---
## License
Please refer to the `LICENSE` file in the repository root for the project license (if present). If no license file exists, the repository's default (copyright) status applies — check the repo settings or ask the maintainer for clarification.
---
## Contact & Links
- Releases: https://github.com/kmmiio99o/ShiggyXposed/releases
- Repository: https://github.com/kmmiio99o/ShiggyXposed
- Support server: https://discord.gg/nQykFF9Ud6
---
Thank you for using ShiggyXposed.

View file

@ -5,23 +5,26 @@ plugins {
} }
android { android {
namespace = "ShiggyXposed.xposed" namespace = "GoonXposed.xposed"
compileSdk = 36 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "ShiggyXposed.xposed" applicationId = "GoonXposed.xposed"
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode = 1350 versionCode = 1358
versionName = "1.3.5" versionName = "1.3.8"
} }
signingConfigs { signingConfigs {
create("release") { create("release") {
storeFile = file("../release.keystore") val keystoreFile = file("../release.keystore")
storePassword = "shiggyxposed" if (keystoreFile.exists()) {
keyAlias = "shiggyxposed" storeFile = keystoreFile
keyPassword = "shiggyxposed" storePassword = "goonxposed"
keyAlias = "goonxposed"
keyPassword = "goonxposed"
}
} }
} }
@ -34,7 +37,10 @@ android {
release { release {
isDebuggable = false isDebuggable = false
isMinifyEnabled = true isMinifyEnabled = true
signingConfig = signingConfigs.getByName("release") val keystoreFile = file("../release.keystore")
if (keystoreFile.exists()) {
signingConfig = signingConfigs.getByName("release")
}
} }
} }
compileOptions { compileOptions {
@ -62,5 +68,6 @@ dependencies {
implementation("io.ktor:ktor-client-core:3.3.1") implementation("io.ktor:ktor-client-core:3.3.1")
implementation("io.ktor:ktor-client-cio:3.3.1") implementation("io.ktor:ktor-client-cio:3.3.1")
implementation("com.google.android.material:material:1.12.0") implementation("com.google.android.material:material:1.12.0")
implementation("dev.rushii:libunbound:1.0.0") implementation("dev.rikka.shizuku:api:13.1.5")
implementation("dev.rikka.shizuku:provider:13.1.5")
} }

View file

@ -13,7 +13,7 @@
<meta-data android:name="xposedmodule" android:value="true" /> <meta-data android:name="xposedmodule" android:value="true" />
<meta-data <meta-data
android:name="xposeddescription" android:name="xposeddescription"
android:value="Xposed module to inject ShiggyCord into discord" android:value="Xposed module to inject GoonCord into discord"
/> />
<meta-data android:name="xposedminversion" android:value="82" /> <meta-data android:name="xposedminversion" android:value="82" />
<meta-data android:name="xposedscope" android:value="com.discord" /> <meta-data android:name="xposedscope" android:value="com.discord" />

View file

@ -1 +1 @@
ShiggyXposed.xposed.Main GoonXposed.xposed.Main

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed package GoonXposed.xposed
class Constants { class Constants {
companion object { companion object {
@ -10,10 +10,10 @@ class Constants {
const val MAIN_SCRIPT_FILE = "bundle.js" const val MAIN_SCRIPT_FILE = "bundle.js"
const val LOG_TAG = "Shiggy" const val LOG_TAG = "Goon"
const val LOADER_NAME = "ShiggyXposed" const val LOADER_NAME = "GoonXposed"
const val USER_AGENT = "ShiggyXposed" const val USER_AGENT = "GoonXposed"
} }
} }

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed package GoonXposed.xposed
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
@ -7,16 +7,15 @@ import android.os.Bundle
import de.robv.android.xposed.IXposedHookLoadPackage import de.robv.android.xposed.IXposedHookLoadPackage
import de.robv.android.xposed.IXposedHookZygoteInit import de.robv.android.xposed.IXposedHookZygoteInit
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import ShiggyXposed.xposed.modules.* import GoonXposed.xposed.modules.*
import ShiggyXposed.xposed.modules.appearance.FontsModule import GoonXposed.xposed.modules.appearance.FontsModule
import ShiggyXposed.xposed.modules.appearance.SysColorsModule import GoonXposed.xposed.modules.appearance.SysColorsModule
import ShiggyXposed.xposed.modules.appearance.ThemesModule import GoonXposed.xposed.modules.appearance.ThemesModule
import ShiggyXposed.xposed.modules.bridge.AdditionalBridgeMethodsModule import GoonXposed.xposed.modules.bridge.AdditionalBridgeMethodsModule
import ShiggyXposed.xposed.modules.bridge.BridgeModule import GoonXposed.xposed.modules.bridge.BridgeModule
import ShiggyXposed.xposed.modules.no_track.BlockCrashReportingModule import GoonXposed.xposed.modules.no_track.BlockCrashReportingModule
import ShiggyXposed.xposed.modules.no_track.BlockDeepLinksTrackingModule import GoonXposed.xposed.modules.no_track.BlockDeepLinksTrackingModule
import ShiggyXposed.xposed.modules.LogBox.*
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
object HookStateHolder { object HookStateHolder {

View file

@ -1,183 +1,161 @@
package ShiggyXposed.xposed package GoonXposed.xposed
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.os.Build import android.content.pm.PackageManager
import de.robv.android.xposed.IXposedHookZygoteInit import de.robv.android.xposed.IXposedHookZygoteInit
import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import kotlinx.serialization.json.JsonObjectBuilder import kotlinx.serialization.json.JsonObjectBuilder
import java.io.File import java.io.File
import java.lang.reflect.Method import java.lang.reflect.Method
/**
* Base class for every Xposed side module.
*
* The [Main] loader forwards the various [XC_LoadPackage] lifecycle callbacks to every
* registered [Module] instance. Modules may override any subset of the hooks below.
*/
open class Module {
open fun onInit(startupParam: IXposedHookZygoteInit.StartupParam) {}
open fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) {}
open fun onContext(context: Context) {}
open fun onActivity(activity: Activity) {}
@Deprecated("This method is deprecated in the parent class")
open fun buildPayload(builder: JsonObjectBuilder) {}
}
/**
* Runtime wrapper around an [XC_MethodHook.MethodHookParam] used as the receiver of every
* `before`/`after` hook block, exposing [thisObject], [args], [result] and [param] directly.
*/
class HookScope(val param: XC_MethodHook.MethodHookParam) {
val thisObject: Any?
get() = param.thisObject
val args: Array<Any?>
get() = param.args
var result: Any?
get() = param.result
set(value) {
param.result = value
}
var throwable: Throwable?
get() = param.throwable
set(value) {
param.throwable = value
}
}
/**
* DSL builder for lazily constructed [XC_MethodHook] instances.
*
* ```kotlin
* val hook = MethodHookBuilder().run {
* before { result = null }
* after { Log.i("done") }
* build()
* }
* ```
*/
class MethodHookBuilder {
private val beforeCallbacks = mutableListOf<HookScope.() -> Unit>()
private val afterCallbacks = mutableListOf<HookScope.() -> Unit>()
fun before(callback: HookScope.() -> Unit) {
beforeCallbacks += callback
}
fun after(callback: HookScope.() -> Unit) {
afterCallbacks += callback
}
fun build(): XC_MethodHook = object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam) {
val scope = HookScope(param)
beforeCallbacks.forEach { scope.run(it) }
}
override fun afterHookedMethod(param: MethodHookParam) {
val scope = HookScope(param)
afterCallbacks.forEach { scope.run(it) }
}
}
companion object {
fun from(block: MethodHookBuilder.() -> Unit): XC_MethodHook = MethodHookBuilder().run {
block()
build()
}
}
}
fun ClassLoader.safeLoadClass(name: String): Class<*>? = try {
loadClass(name)
} catch (e: Throwable) {
null
}
fun Class<*>.method(name: String, vararg parameterTypes: Class<*>): Method =
XposedHelpers.findMethodExact(this, name, *parameterTypes)
fun Method.hook(block: MethodHookBuilder.() -> Unit) {
val builder = MethodHookBuilder()
builder.block()
XposedBridge.hookMethod(this, builder.build())
}
fun Method.hook(hook: XC_MethodHook) {
XposedBridge.hookMethod(this, hook)
}
fun Class<*>.hookMethod(
name: String,
vararg parameterTypes: Class<*>,
block: MethodHookBuilder.() -> Unit
): Method {
val method = method(name, *parameterTypes)
method.hook(block)
return method
}
fun File.asDir(): File {
if (!exists() || !isDirectory) mkdirs()
return this
}
fun File.asFile(): File {
parentFile?.mkdirs()
return this
}
data class AppInfo( data class AppInfo(
val name: String, val name: String,
val packageName: String, val packageName: String,
val version: String, val version: String,
val versionCode: Long, val versionCode: Int
) )
abstract class Module { fun Context.getAppInfo(): AppInfo {
/** val label = applicationInfo.loadLabel(packageManager).toString()
* Builds a JSON payload to be injected into the JavaScript context. val packageInfo = try {
*/ packageManager.getPackageInfo(packageName, 0)
@Deprecated("This will be removed in future versions. Payloads can be replaced via synchronous bridge methods.") } catch (e: PackageManager.NameNotFoundException) {
open fun buildPayload(builder: JsonObjectBuilder) { null
} }
/** return AppInfo(
* Called during Zygote initialization. name = label,
*/ packageName = packageName,
open fun onInit(startupParam: IXposedHookZygoteInit.StartupParam) {} version = packageInfo?.versionName ?: "",
versionCode = packageInfo?.versionCode ?: 0
/** )
* Called when a package is loaded.
*
* Hooks should typically be set up here.
*
* Bridge methods that do not require [Context] can also be registered here.
*/
open fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) {}
/**
* Called after [Context] has been attached to a [android.content.ContextWrapper]
* via [android.content.ContextWrapper.attachBaseContext].
*
* This may be called multiple times for different [Context]s, e.g. when the app is killed by the system.
*
* For bridge methods that require access to [Context], register them here.
*/
open fun onContext(context: Context) {}
/**
* Called after an [Activity.onCreate] method is executed.
*
* UI code that requires an [Activity] context can be placed here.
*
* Bridge methods must not be registered here, as it can be too late and cause crashes.
*
* If you need to register bridge methods that require an [Activity], do it in [onContext] and make it async.
*
* Once an [Activity] is available, execute the queued calls. Then from JS, call the method asynchronously.
*/
open fun onActivity(activity: Activity) {}
protected fun Context.getAppInfo(): AppInfo {
val pInfo = packageManager.getPackageInfo(packageName, 0)
val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) pInfo.longVersionCode
else @Suppress("DEPRECATION") pInfo.versionCode.toLong()
return AppInfo(
packageManager.getApplicationLabel(applicationInfo).toString(),
packageName,
pInfo.versionName ?: versionCode.toString(),
versionCode,
)
}
protected fun File.asDir() {
if (!this.isDirectory) this.delete()
this.mkdirs()
}
protected fun File.asFile() {
if (!this.isFile) this.deleteRecursively()
}
protected fun Class<*>.method(
name: String, vararg params: Class<*>?
): Method = getDeclaredMethod(name, *params).apply {
isAccessible = true
}
protected fun ClassLoader.safeLoadClass(name: String): Class<*>? = runCatching { loadClass(name) }.getOrNull()
protected fun Method.hook(hook: XC_MethodHook): XC_MethodHook.Unhook = XposedBridge.hookMethod(this, hook)
protected fun Method.hook(block: MethodHookBuilder.() -> Unit): XC_MethodHook.Unhook =
hook(MethodHookBuilder().apply(block).build())
protected fun Class<*>.hookMethod(
name: String, vararg params: Class<*>?, block: MethodHookBuilder.() -> Unit
): XC_MethodHook.Unhook = method(name, *params).hook(MethodHookBuilder().apply(block).build())
protected class MethodHookBuilder {
private var beforeBlock: (HookScope.() -> Unit)? = null
private var afterBlock: (HookScope.() -> Unit)? = null
fun before(block: HookScope.() -> Unit) {
beforeBlock = block
}
fun after(block: HookScope.() -> Unit) {
afterBlock = block
}
fun build(): XC_MethodHook = object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam) {
val b = beforeBlock
if (b != null) {
val scope = HookScope(
param = param, proceed = { p ->
super.beforeHookedMethod(p)
})
scope.b()
} else {
super.beforeHookedMethod(param)
}
}
override fun afterHookedMethod(param: MethodHookParam) {
val a = afterBlock
if (a != null) {
val scope = HookScope(
param = param, proceed = { p ->
super.afterHookedMethod(p)
})
scope.a()
} else {
super.afterHookedMethod(param)
}
}
}
}
/**
* Scope object passed to before/after hook blocks.
*
* Provides:
* - Access to the [param] object
* - [proceed] to call the original XC_MethodHook super method
* - Accessors for `thisObject`, `args`, `result`, and `throwable`
*
* @property param The [XC_MethodHook.MethodHookParam] for the current hook.
* @property proceed Function that calls the super method.
*/
protected class HookScope internal constructor(
val param: XC_MethodHook.MethodHookParam, private val proceed: (XC_MethodHook.MethodHookParam) -> Unit
) {
/**
* Continues with the default XC_MethodHook super behavior.
* Equivalent to calling `super.beforeHookedMethod(param)` or
* `super.afterHookedMethod(param)` depending on the phase.
*/
fun proceed() = proceed(param)
val thisObject: Any? get() = param.thisObject
val args: Array<Any?> get() = param.args
var result: Any?
get() = param.result
set(value) {
param.result = value
}
var throwable: Throwable?
get() = param.throwable
set(value) {
param.throwable = value
}
}
} }

View file

@ -1,10 +1,11 @@
package ShiggyXposed.xposed package GoonXposed.xposed
import android.app.AlertDialog import android.app.AlertDialog
import android.app.AndroidAppHelper import android.app.Application
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import ShiggyXposed.xposed.modules.UpdaterModule import de.robv.android.xposed.XposedHelpers
import GoonXposed.xposed.modules.UpdaterModule
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.io.File import java.io.File
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -14,14 +15,16 @@ class Utils {
val JSON = Json { ignoreUnknownKeys = true } val JSON = Json { ignoreUnknownKeys = true }
fun reloadApp() { fun reloadApp() {
val application = AndroidAppHelper.currentApplication() val activityThread = XposedHelpers.findClass("android.app.ActivityThread", null)
val application =
XposedHelpers.callStaticMethod(activityThread, "currentApplication") as? Application ?: return
val intent = application.packageManager.getLaunchIntentForPackage(application.packageName) val intent = application.packageManager.getLaunchIntentForPackage(application.packageName)
application.startActivity(Intent.makeRestartActivityTask(intent!!.component)) application.startActivity(Intent.makeRestartActivityTask(intent!!.component))
exitProcess(0) exitProcess(0)
} }
fun showRecoveryAlert(context: Context) { fun showRecoveryAlert(context: Context) {
AlertDialog.Builder(context).setTitle("ShiggyCord Recovery Options") AlertDialog.Builder(context).setTitle("GoonCord Recovery Options")
.setItems(arrayOf("Reload", "Delete Script", "Reset Loader Config")) { _, which -> .setItems(arrayOf("Reload", "Delete Script", "Reset Loader Config")) { _, which ->
when (which) { when (which) {
0 -> { 0 -> {

View file

@ -1,10 +1,13 @@
package ShiggyXposed.xposed.modules package GoonXposed.xposed.modules
import android.content.Context import android.content.Context
import android.util.AtomicFile import android.util.AtomicFile
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import ShiggyXposed.xposed.modules.bridge.BridgeModule import GoonXposed.xposed.asDir
import GoonXposed.xposed.asFile
import GoonXposed.xposed.getAppInfo
import GoonXposed.xposed.modules.bridge.BridgeModule
import java.io.* import java.io.*
/** /**
@ -35,7 +38,7 @@ import java.io.*
*/ */
object CacheModule : Module() { object CacheModule : Module() {
private const val CACHE_DIR = "Shiggy" private const val CACHE_DIR = "Goon"
private const val MODULES_CACHE_PREFIX = "modules" private const val MODULES_CACHE_PREFIX = "modules"
private const val ASSETS_CACHE_PREFIX = "assets" private const val ASSETS_CACHE_PREFIX = "assets"

View file

@ -1,9 +1,11 @@
package ShiggyXposed.xposed.modules package GoonXposed.xposed.modules
import GoonXposed.xposed.hookMethod
import android.content.res.Resources import android.content.res.Resources
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.Constants.Companion.TARGET_PACKAGE import GoonXposed.xposed.Constants.Companion.TARGET_PACKAGE
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import GoonXposed.xposed.hookMethod
/** /**
* Hooks [Resources.getIdentifier] to fix resource package name mismatch. * Hooks [Resources.getIdentifier] to fix resource package name mismatch.

View file

@ -1,15 +1,21 @@
package ShiggyXposed.xposed.modules package GoonXposed.xposed.modules
import android.content.res.AssetManager import android.content.res.AssetManager
import android.content.res.XModuleResources import android.content.res.XModuleResources
import de.robv.android.xposed.IXposedHookZygoteInit import de.robv.android.xposed.IXposedHookZygoteInit
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Constants
import ShiggyXposed.xposed.HookStateHolder import GoonXposed.xposed.HookScope
import ShiggyXposed.xposed.Module import GoonXposed.xposed.HookStateHolder
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Module
import ShiggyXposed.xposed.modules.HookScriptLoaderModule.PRELOADS_DIR import GoonXposed.xposed.Utils.Log
import GoonXposed.xposed.asDir
import GoonXposed.xposed.asFile
import GoonXposed.xposed.hook
import GoonXposed.xposed.method
import GoonXposed.xposed.safeLoadClass
import GoonXposed.xposed.modules.HookScriptLoaderModule.PRELOADS_DIR
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -54,11 +60,11 @@ object HookScriptLoaderModule : Module() {
private fun hook(instance: Class<*>) = runCatching { private fun hook(instance: Class<*>) = runCatching {
val loadScriptFromAssets = instance.method( val loadScriptFromAssets = instance.method(
"loadScriptFromAssets", AssetManager::class.java, String::class.java, Boolean::class.javaPrimitiveType "loadScriptFromAssets", AssetManager::class.java, String::class.java, Boolean::class.javaPrimitiveType!!
) )
val loadScriptFromFile = instance.method( val loadScriptFromFile = instance.method(
"loadScriptFromFile", String::class.java, String::class.java, Boolean::class.javaPrimitiveType "loadScriptFromFile", String::class.java, String::class.java, Boolean::class.javaPrimitiveType!!
) )
loadScriptFromAssets.hook { loadScriptFromAssets.hook {
@ -83,17 +89,14 @@ object HookScriptLoaderModule : Module() {
runBlocking { runBlocking {
val ready = async { HookStateHolder.readyDeferred.join() } val ready = async { HookStateHolder.readyDeferred.join() }
val isCustomUrl = UpdaterModule.isCustomUrlEnabled
if (!mainScript.exists() || isCustomUrl) { if (!mainScript.exists()) {
val reason = if (isCustomUrl) "Custom URL enabled" else "Main script does not exist" Log.i("Main script does not exist, downloading before load...")
Log.i("$reason, downloading before load...") val download = async { UpdaterModule.downloadScript().join() }
val download =
async { UpdaterModule.downloadScript(showUpdateDialog = false).join() }
awaitAll(ready, download) awaitAll(ready, download)
} else { } else {
Log.i("Main script exists, updating in background...") Log.i("Main script exists, updating in background...")
UpdaterModule.downloadScript(showUpdateDialog = true) UpdaterModule.downloadScript()
ready.await() ready.await()
} }
} }
@ -110,14 +113,10 @@ object HookScriptLoaderModule : Module() {
} }
try { try {
// If a disabled marker exists next to the cached bundle, treat this as a global
// disable for the entire script-loading step. In that case, we skip preloads,
// cached main script and the assets fallback so nothing is injected.
val disabledMarker = File(mainScript.parentFile, "${Constants.MAIN_SCRIPT_FILE}.disabled") val disabledMarker = File(mainScript.parentFile, "${Constants.MAIN_SCRIPT_FILE}.disabled")
if (disabledMarker.exists()) { if (disabledMarker.exists()) {
Log.i("Script loading disabled by marker; skipping preloads, cached bundle and fallback") Log.i("Script loading disabled by marker; skipping preloads, cached bundle and fallback")
} else { } else {
// Normal behaviour: run preloads then cached main script or fallback to bundled asset
preloadsDir.walk().filter { it.isFile }.forEach(runScriptFile) preloadsDir.walk().filter { it.isFile }.forEach(runScriptFile)
if (mainScript.exists()) { if (mainScript.exists()) {

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
@ -62,7 +62,7 @@ object CustomBundleDialog {
container.addView(toggleContainer) container.addView(toggleContainer)
val urlInput = EditText(context).apply { val urlInput = EditText(context).apply {
hint = "http://localhost:4040/shiggycord.js" hint = "http://localhost:4040/gooncord.js"
setTextColor(colors.onSurface) setTextColor(colors.onSurface)
setHintTextColor(colors.onSurfaceVariant) setHintTextColor(colors.onSurfaceVariant)
background = LogBoxUtils.createM3Background(context, colors.surfaceVariant, 12f) background = LogBoxUtils.createM3Background(context, colors.surfaceVariant, 12f)

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context

View file

@ -1,12 +1,12 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.content.Context import android.content.Context
import android.widget.Toast import android.widget.Toast
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import ShiggyXposed.xposed.Utils.Companion.reloadApp import GoonXposed.xposed.Utils.Companion.reloadApp
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Constants
import kotlinx.coroutines.* import kotlinx.coroutines.*
object LogBoxActions { object LogBoxActions {
@ -134,7 +134,7 @@ object LogBoxActions {
val config = JSONObject(configFile.readText()) val config = JSONObject(configFile.readText())
val customLoadUrl = config.optJSONObject("customLoadUrl") ?: JSONObject() val customLoadUrl = config.optJSONObject("customLoadUrl") ?: JSONObject()
customLoadUrl.put("enabled", false) customLoadUrl.put("enabled", false)
customLoadUrl.put("url", "http://localhost:4040/shiggycord.js") customLoadUrl.put("url", "http://localhost:4040/gooncord.js")
config.put("customLoadUrl", customLoadUrl) config.put("customLoadUrl", customLoadUrl)
configFile.writeText(config.toString()) configFile.writeText(config.toString())
} }

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.graphics.Color import android.graphics.Color

View file

@ -1,11 +1,11 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
object LogBoxDialogs { object LogBoxDialogs {

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
@ -14,8 +14,8 @@ import android.content.res.ColorStateList
import android.view.animation.DecelerateInterpolator import android.view.animation.DecelerateInterpolator
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import ShiggyXposed.xposed.Utils import GoonXposed.xposed.Utils
object LogBoxMenu { object LogBoxMenu {
@ -30,7 +30,7 @@ object LogBoxMenu {
val container = createMenuContainer(context, colors) val container = createMenuContainer(context, colors)
// Title // Title
container.addView(createTitle(context, colors, "ShiggyXposed Recovery", center = true)) container.addView(createTitle(context, colors, "GoonXposed Recovery", center = true))
// Subtitle // Subtitle
container.addView(createSubtitle(context, colors, "Select an option to continue")) container.addView(createSubtitle(context, colors, "Select an option to continue"))
@ -782,7 +782,7 @@ object LogBoxMenu {
) { LogBoxActions.refetchBundle(context) } ) { LogBoxActions.refetchBundle(context) }
2 -> showCustomBundleDialog(context) 2 -> showCustomBundleDialog(context)
3 -> ShiggyXposed.xposed.Utils.Companion.reloadApp() 3 -> Utils.reloadApp()
4 -> showConfirmAction( 4 -> showConfirmAction(
context, "Clear Cache & Reset", context, "Clear Cache & Reset",
"This will clear all cached bundles and reset to default settings." "This will clear all cached bundles and reset to default settings."

View file

@ -1,8 +1,10 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import GoonXposed.xposed.Utils.Companion.reloadApp
import android.content.Context import android.content.Context
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XC_MethodReplacement import de.robv.android.xposed.XC_MethodReplacement
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers import de.robv.android.xposed.XposedHelpers
@ -22,11 +24,15 @@ object LogBoxModule : Module() {
val getUseDeveloperSupportMethod = val getUseDeveloperSupportMethod =
dcdReactNativeHostClass.methods.first { it.name == "getUseDeveloperSupport" } dcdReactNativeHostClass.methods.first { it.name == "getUseDeveloperSupport" }
getUseDeveloperSupportMethod.hook { // NOTE: This used to call a custom `.hook { before { result = true } }` DSL that
before { // relied on a shared extensions file which broke (unresolved references).
result = true // Rewritten using the standard XposedBridge/XC_MethodHook API, which is already
// used elsewhere in this file, to force this method to always return true.
XposedBridge.hookMethod(getUseDeveloperSupportMethod, object : XC_MethodHook() {
override fun beforeHookedMethod(param: MethodHookParam) {
param.result = true
} }
} })
Log.e("Successfully hooked DCDReactNativeHost") Log.e("Successfully hooked DCDReactNativeHost")
} catch (e: Exception) { } catch (e: Exception) {
Log.e("Failed to hook DCDReactNativeHost: ${e.message}") Log.e("Failed to hook DCDReactNativeHost: ${e.message}")
@ -95,7 +101,7 @@ object LogBoxModule : Module() {
XposedBridge.hookMethod(handleReloadJSMethod, object : XC_MethodReplacement() { XposedBridge.hookMethod(handleReloadJSMethod, object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam): Any? { override fun replaceHookedMethod(param: MethodHookParam): Any? {
Log.e("handleReloadJS called - reloading app") Log.e("handleReloadJS called - reloading app")
ShiggyXposed.xposed.Utils.Companion.reloadApp() reloadApp()
return null return null
} }
}) })

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.content.Context import android.content.Context

View file

@ -1,10 +1,10 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
object LogBoxTheme { object LogBoxTheme {

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.content.Context import android.content.Context
import android.util.TypedValue import android.util.TypedValue
@ -9,8 +9,8 @@ import android.view.View
import android.widget.Toast import android.widget.Toast
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Constants
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
object LogBoxUtils { object LogBoxUtils {

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
@ -19,40 +19,29 @@ object OptionsMenu {
container.addView(LogBoxComponents.createM3Button(context, injectionText, colors) { container.addView(LogBoxComponents.createM3Button(context, injectionText, colors) {
dialog.dismiss() dialog.dismiss()
LogBoxActions.toggleBundleInjection(context) LogBoxActions.toggleBundleInjection(context)
GoonXposed.xposed.Utils.Companion.reloadApp()
}) })
container.addView(LogBoxComponents.createM3Button(context, "Refetch Bundle", colors) { container.addView(LogBoxComponents.createM3Button(context, "Refetch Bundle", colors) {
dialog.dismiss() dialog.dismiss()
RecoveryMenu::class.java.getDeclaredMethod( RecoveryMenu.showConfirmAction(
"showConfirmAction",
Context::class.java,
String::class.java,
String::class.java,
Runnable::class.java
).apply { isAccessible = true }.invoke(
null,
context, context,
"Refetch Bundle", "Refetch Bundle",
"This will download the latest bundle from Github.", "This will download the latest bundle from Github."
Runnable { LogBoxActions.refetchBundle(context) } ) {
) LogBoxActions.refetchBundle(context)
}
}) })
container.addView(LogBoxComponents.createM3Button(context, "Clear Cache & Reset", colors) { container.addView(LogBoxComponents.createM3Button(context, "Clear Cache & Reset", colors) {
dialog.dismiss() dialog.dismiss()
RecoveryMenu::class.java.getDeclaredMethod( RecoveryMenu.showConfirmAction(
"showConfirmAction",
Context::class.java,
String::class.java,
String::class.java,
Runnable::class.java
).apply { isAccessible = true }.invoke(
null,
context, context,
"Clear Cache & Reset", "Clear Cache & Reset",
"This will clear all cached bundles and reset to default settings.", "This will clear all cached bundles and reset to default settings."
Runnable { LogBoxActions.clearCacheAndReset(context) } ) {
) LogBoxActions.clearCacheAndReset(context)
}
}) })
container.addView(LogBoxComponents.createM3Button(context, "Back", colors) { container.addView(LogBoxComponents.createM3Button(context, "Back", colors) {

View file

@ -1,9 +1,9 @@
package ShiggyXposed.xposed.modules.LogBox package GoonXposed.xposed.modules.LogBox
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.widget.LinearLayout import android.widget.LinearLayout
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
object RecoveryMenu { object RecoveryMenu {
@ -15,7 +15,7 @@ object RecoveryMenu {
val container = LogBoxComponents.createMenuContainer(context, colors) val container = LogBoxComponents.createMenuContainer(context, colors)
container.addView(LogBoxComponents.createTitle(context, colors, "ShiggyXposed Recovery", center = true)) container.addView(LogBoxComponents.createTitle(context, colors, "GoonXposed Recovery", center = true))
container.addView(LogBoxComponents.createSubtitle(context, colors, "Select an option to continue")) container.addView(LogBoxComponents.createSubtitle(context, colors, "Select an option to continue"))
val safeModeText = if (LogBoxUtils.isSafeModeEnabled(context)) "Disable Safe Mode" else "Enable Safe Mode" val safeModeText = if (LogBoxUtils.isSafeModeEnabled(context)) "Disable Safe Mode" else "Enable Safe Mode"
@ -63,7 +63,7 @@ object RecoveryMenu {
} }
2 -> CustomBundleDialog.showCustomBundleDialog(context) 2 -> CustomBundleDialog.showCustomBundleDialog(context)
3 -> ShiggyXposed.xposed.Utils.Companion.reloadApp() 3 -> GoonXposed.xposed.Utils.Companion.reloadApp()
4 -> showConfirmAction( 4 -> showConfirmAction(
context, context,
"Clear Cache & Reset", "Clear Cache & Reset",
@ -76,7 +76,7 @@ object RecoveryMenu {
} }
} }
private fun showConfirmAction(context: Context, title: String, message: String, action: () -> Unit) { fun showConfirmAction(context: Context, title: String, message: String, action: () -> Unit) {
val colors = LogBoxTheme.getM3Colors(context) val colors = LogBoxTheme.getM3Colors(context)
val container = LogBoxComponents.createMenuContainer(context, colors) val container = LogBoxComponents.createMenuContainer(context, colors)

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,18 @@
package ShiggyXposed.xposed.modules package GoonXposed.xposed.modules
import android.content.res.AssetManager import android.content.res.AssetManager
import de.robv.android.xposed.XC_MethodHook import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.BuildConfig import GoonXposed.xposed.BuildConfig
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Constants
import ShiggyXposed.xposed.Module import GoonXposed.xposed.MethodHookBuilder
import ShiggyXposed.xposed.Utils.Companion.JSON import GoonXposed.xposed.Module
import ShiggyXposed.xposed.modules.HookScriptLoaderModule.PRELOADS_DIR import GoonXposed.xposed.Utils.Companion.JSON
import GoonXposed.xposed.hook
import GoonXposed.xposed.method
import GoonXposed.xposed.safeLoadClass
import GoonXposed.xposed.modules.HookScriptLoaderModule.PRELOADS_DIR
import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put import kotlinx.serialization.json.put
import java.io.File import java.io.File
@ -48,7 +52,7 @@ class PayloadGlobalModule(private val modules: List<Module>) : Module() {
"loadScriptFromFile", "loadScriptFromFile",
String::class.java, String::class.java,
String::class.java, String::class.java,
Boolean::class.javaPrimitiveType Boolean::class.javaPrimitiveType!!
), param.thisObject, arrayOf(absolutePath, absolutePath, param.args[2]) ), param.thisObject, arrayOf(absolutePath, absolutePath, param.args[2])
) )
@ -70,11 +74,11 @@ class PayloadGlobalModule(private val modules: List<Module>) : Module() {
private fun hook(instance: Class<*>, hook: XC_MethodHook) { private fun hook(instance: Class<*>, hook: XC_MethodHook) {
instance.method( instance.method(
"loadScriptFromAssets", AssetManager::class.java, String::class.java, Boolean::class.javaPrimitiveType, "loadScriptFromAssets", AssetManager::class.java, String::class.java, Boolean::class.javaPrimitiveType!!,
).hook(hook) ).hook(hook)
instance.method( instance.method(
"loadScriptFromFile", String::class.java, String::class.java, Boolean::class.javaPrimitiveType "loadScriptFromFile", String::class.java, String::class.java, Boolean::class.javaPrimitiveType!!
).hook(hook) ).hook(hook)
} }
} }

View file

@ -1,11 +1,11 @@
package ShiggyXposed.xposed.modules package GoonXposed.xposed.modules
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import kotlinx.serialization.json.JsonObjectBuilder import kotlinx.serialization.json.JsonObjectBuilder
import kotlinx.serialization.json.put import kotlinx.serialization.json.put
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Constants
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import java.io.File import java.io.File
/** /**

View file

@ -1,10 +1,11 @@
package ShiggyXposed.xposed.modules package GoonXposed.xposed.modules
import android.content.Context import android.content.Context
import android.util.AtomicFile import android.util.AtomicFile
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import ShiggyXposed.xposed.modules.bridge.BridgeModule import GoonXposed.xposed.asFile
import GoonXposed.xposed.modules.bridge.BridgeModule
import java.io.* import java.io.*
/** /**

View file

@ -1,18 +1,18 @@
package ShiggyXposed.xposed.modules package GoonXposed.xposed.modules
import android.app.Activity import android.app.Activity
import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.util.AtomicFile import android.util.AtomicFile
import android.widget.Toast import android.widget.Toast
import androidx.core.util.writeBytes
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import dev.rushii.libunbound.LibUnbound import GoonXposed.xposed.Constants
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Utils
import ShiggyXposed.xposed.Utils import GoonXposed.xposed.Utils.Companion.JSON
import ShiggyXposed.xposed.Utils.Companion.JSON import GoonXposed.xposed.Utils.Companion.reloadApp
import GoonXposed.xposed.Utils.Log
import ShiggyXposed.xposed.Utils.Log
import ShiggyXposed.xposed.modules.bridge.BridgeModule
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.call.* import io.ktor.client.call.*
import io.ktor.client.engine.cio.* import io.ktor.client.engine.cio.*
@ -22,41 +22,46 @@ import io.ktor.client.statement.*
import io.ktor.http.* import io.ktor.http.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.encodeToString
import java.io.File import java.io.File
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@Serializable @Serializable
data class CustomLoadUrl(val enabled: Boolean = false, val url: String = "") data class CustomLoadUrl(
val enabled: Boolean = false, val url: String = ""
)
@Serializable @Serializable
data class LoaderConfig(val customLoadUrl: CustomLoadUrl = CustomLoadUrl(), val disableInjection: Boolean = false) data class LoaderConfig(
val customLoadUrl: CustomLoadUrl = CustomLoadUrl()
@Serializable )
data class EndpointInfo(val paths: ArrayList<String>, val hash: String? = null, val version: String)
/**
* Module that updates the JS bundle by downloading it from a remote URL.
*
* Shows dialogs when failed allowing retry.
*/
object UpdaterModule : Module() { object UpdaterModule : Module() {
private lateinit var config: LoaderConfig private lateinit var config: LoaderConfig
val isCustomUrlEnabled: Boolean
get() = config.customLoadUrl.enabled
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private var lastActivity: WeakReference<Activity>? = null private var lastActivity: WeakReference<Activity>? = null
private lateinit var cacheDir: File private lateinit var cacheDir: File
private lateinit var bundle: File private lateinit var bundle: File
private lateinit var etag: File private lateinit var etag: File
// Path to the application's data directory so we can read LogBox settings
private lateinit var appDataDir: File
private const val TIMEOUT_STRICT = 15000L private const val TIMEOUT_CACHED = 5000L
private const val MIN_BYTECODE_SIZE = 512 private const val TIMEOUT = 10000L
private const val ETAG_FILE = "etag.txt" private const val ETAG_FILE = "etag.txt"
private const val CONFIG_FILE = "loader.json" private const val CONFIG_FILE = "loader.json"
private const val DEFAULT_BASE_URL = "https://github.com/kmmiio99o/ShiggyCord/releases/latest/download/" private const val DEFAULT_BUNDLE_URL =
private const val FALLBACK_BASE_URL = "https://bundle.shiggycord.dev/" "https://github.com/OTKUSteyler/GoonCord/releases/latest/download/gooncord.js"
private const val DEFAULT_BUNDLE_NAME = "shiggycord.min.js"
override fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) = with(packageParam) { override fun onLoad(packageParam: XC_LoadPackage.LoadPackageParam) = with(packageParam) {
// store app data dir for later checks (LogBox settings live under files/logbox)
appDataDir = File(appInfo.dataDir)
cacheDir = File(appInfo.dataDir, Constants.CACHE_DIR).apply { mkdirs() } cacheDir = File(appInfo.dataDir, Constants.CACHE_DIR).apply { mkdirs() }
val filesDir = File(appInfo.dataDir, Constants.FILES_DIR).apply { mkdirs() } val filesDir = File(appInfo.dataDir, Constants.FILES_DIR).apply { mkdirs() }
@ -64,100 +69,91 @@ object UpdaterModule : Module() {
etag = File(cacheDir, ETAG_FILE) etag = File(cacheDir, ETAG_FILE)
val configFile = File(filesDir, CONFIG_FILE) val configFile = File(filesDir, CONFIG_FILE)
config = runCatching {
if (configFile.exists()) JSON.decodeFromString<LoaderConfig>(configFile.readText()) else LoaderConfig()
}.getOrDefault(LoaderConfig())
BridgeModule.registerMethod("revenge.updater.clear") { config = runCatching {
if (bundle.exists()) bundle.delete() if (configFile.exists()) {
if (etag.exists()) etag.delete() JSON.decodeFromString<LoaderConfig>(configFile.readText())
null } else LoaderConfig()
} }.getOrDefault(LoaderConfig())
} }
fun downloadScript(activity: Activity? = null, showUpdateDialog: Boolean = true): Job = scope.launch { fun downloadScript(activity: Activity? = null): Job = scope.launch {
try { try {
// Respect LogBox setting to disable bundle injections.
// If the file "files/logbox/LOGBOX_SETTINGS" contains the flag bundleInjectionDisabled=true,
// skip attempting to download/update the bundle.
try {
val settingsFile = File(appDataDir, "files/logbox/LOGBOX_SETTINGS")
if (settingsFile.exists()) {
val txt = settingsFile.readText()
// look for a simple true marker; this avoids introducing a new JSON dependency here
if (txt.contains("\"bundleInjectionDisabled\"") && txt.contains("true")) {
Log.i("UpdaterModule: bundle injection disabled by LogBox settings — skipping download")
return@launch
}
}
} catch (ignore: Exception) {
// If anything goes wrong reading the setting, proceed with normal behaviour.
}
HttpClient(CIO) { HttpClient(CIO) {
expectSuccess = false expectSuccess = false
install(HttpTimeout) {
requestTimeoutMillis = TIMEOUT_STRICT
connectTimeoutMillis = 5000L
socketTimeoutMillis = TIMEOUT_STRICT
}
install(UserAgent) { agent = Constants.USER_AGENT } install(UserAgent) { agent = Constants.USER_AGENT }
install(HttpRedirect) { checkHttpMethod = false } install(HttpRedirect) {}
}.use { client -> }.use { client ->
val targetUrl = resolveTargetUrl(client) val url = config.customLoadUrl.takeIf { it.enabled }?.url ?: DEFAULT_BUNDLE_URL
Log.i("Fetching bundle: $targetUrl") Log.i("Fetching JS bundle from: $url")
val response: HttpResponse = client.get(targetUrl) { val response: HttpResponse = client.get(url) {
headers { headers {
if (etag.exists() && bundle.exists()) { if (etag.exists() && bundle.exists()) {
append(HttpHeaders.IfNoneMatch, etag.readText()) append(HttpHeaders.IfNoneMatch, etag.readText())
} }
} }
// Retries don't need timeout
if (activity == null) {
timeout {
requestTimeoutMillis = if (!bundle.exists()) TIMEOUT else TIMEOUT_CACHED
}
}
} }
when (response.status) { when (response.status) {
HttpStatusCode.OK -> { HttpStatusCode.OK -> {
val bytes: ByteArray = response.body() val bytes: ByteArray = response.body()
AtomicFile(bundle).writeBytes(bytes)
if (bytes.size < MIN_BYTECODE_SIZE) { val newTag = response.headers[HttpHeaders.ETag]
throw Exception("Payload too small (${bytes.size} bytes). Possible corrupt build.") if (!newTag.isNullOrEmpty()) etag.writeText(newTag) else etag.delete()
}
AtomicFile(bundle).apply { Log.i("Bundle updated (${bytes.size} bytes)")
val stream = startWrite()
try { // This is a retry, so we show a dialog
stream.write(bytes) if (activity != null) {
finishWrite(stream) withContext(Dispatchers.Main) {
} catch (e: Exception) { AlertDialog.Builder(activity).setTitle("GoonCord Update Successful")
failWrite(stream) .setMessage("A reload is required for changes to take effect.")
throw e .setPositiveButton("Reload") { dialog, _ ->
reloadApp()
dialog.dismiss()
}.setCancelable(false).show()
} }
} }
response.headers[HttpHeaders.ETag]?.let { etag.writeText(it) } ?: etag.delete()
Log.i("Bundle updated: ${bytes.size} bytes")
} }
HttpStatusCode.NotModified -> Log.i("Bundle is up to date (304)") HttpStatusCode.NotModified -> {
else -> throw ResponseException(response, "HTTP ${response.status}") Log.i("Server responded with 304, no changes")
}
else -> {
throw ResponseException(response, "Received status: ${response.status}")
}
} }
} }
} catch (e: Throwable) { } catch (e: Throwable) {
Log.e("Updater Error", e) Log.e("Failed to download script", e)
} showErrorDialog(e)
}
private suspend fun resolveTargetUrl(client: HttpClient): String {
if (config.customLoadUrl.enabled && config.customLoadUrl.url.isNotEmpty()) {
return config.customLoadUrl.url
}
return tryResolveUrl(client, DEFAULT_BASE_URL)
?: tryResolveUrl(client, FALLBACK_BASE_URL)
?: DEFAULT_BASE_URL + DEFAULT_BUNDLE_NAME
}
private suspend fun tryResolveUrl(client: HttpClient, baseUrl: String): String? {
return try {
val infoResponse = client.get("${baseUrl}info.json")
if (infoResponse.status == HttpStatusCode.OK) {
val info = JSON.decodeFromString<EndpointInfo>(infoResponse.bodyAsText())
val hermesVersion = withTimeoutOrNull(2000L) {
runCatching { LibUnbound.getHermesRuntimeBytecodeVersion() }.getOrNull()
} ?: 96
val hbcName = "shiggycord.$hermesVersion.hbc"
when {
info.paths.contains(hbcName) -> baseUrl + hbcName
info.paths.contains("shiggycord.min.js") -> baseUrl + "shiggycord.min.js"
else -> baseUrl + DEFAULT_BUNDLE_NAME
}
} else null
} catch (e: Exception) {
null
} }
} }
@ -165,16 +161,16 @@ object UpdaterModule : Module() {
lastActivity = WeakReference(activity) lastActivity = WeakReference(activity)
} }
fun setDisableInjection(context: Context, disabled: Boolean) { fun showErrorDialog(e: Throwable) {
val filesDir = File(context.dataDir, Constants.FILES_DIR).apply { mkdirs() } val activity = lastActivity?.get() ?: return
val configFile = File(filesDir, CONFIG_FILE)
val newCfg = config.copy(disableInjection = disabled) activity.runOnUiThread {
configFile.writeText(JSON.encodeToString(newCfg)) }
config = newCfg
Toast.makeText(context, "Injection ${if (disabled) "disabled" else "enabled"}", Toast.LENGTH_SHORT).show()
} }
fun isInjectionDisabled(context: Context? = null): Boolean { fun resetLoaderConfig(context: Context) {
return if (::config.isInitialized) config.disableInjection else false val filesDir = File(context.dataDir, Constants.FILES_DIR)
val config = File(filesDir, CONFIG_FILE)
if (config.exists()) config.delete()
} }
} }

View file

@ -1,4 +1,6 @@
package ShiggyXposed.xposed.modules.appearance @file:Suppress("DEPRECATION")
package GoonXposed.xposed.modules.appearance
import android.content.res.AssetManager import android.content.res.AssetManager
import android.graphics.Typeface import android.graphics.Typeface
@ -9,10 +11,10 @@ import android.os.Build
import de.robv.android.xposed.XC_MethodReplacement import de.robv.android.xposed.XC_MethodReplacement
import de.robv.android.xposed.XposedHelpers import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Constants
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils.Companion.JSON import GoonXposed.xposed.Utils.Companion.JSON
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.call.* import io.ktor.client.call.*
import io.ktor.client.engine.cio.* import io.ktor.client.engine.cio.*
@ -27,6 +29,14 @@ import kotlinx.serialization.json.put
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
// NOTE: These extensions used to be resolved from a shared Utils/Extensions file,
// but that reference broke (renamed/removed/relocated), causing "Unresolved reference"
// build failures. Defining them locally here removes the dependency on that file.
// asFile(): ensures the parent directory of a file exists.
// asDir(): ensures the directory itself exists.
private fun File.asFile(): File = apply { parentFile?.mkdirs() }
private fun File.asDir(): File = apply { mkdirs() }
@Serializable @Serializable
data class FontDefinition( data class FontDefinition(
val name: String? = null, val name: String? = null,
@ -93,28 +103,40 @@ object FontsModule : Module() {
// These files should be downloaded by the JS side, but oh well // These files should be downloaded by the JS side, but oh well
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
fontDef.main.keys.map { name -> val client = HttpClient(CIO) {
async { install(UserAgent) { agent = Constants.USER_AGENT }
val url = fontDef.main.getValue(name) install(HttpTimeout) {
try { requestTimeoutMillis = 15_000
Log.i("Downloading $name from $url") connectTimeoutMillis = 10_000
val file = socketTimeoutMillis = 15_000
File(fontsDir, "$name${FILE_EXTENSIONS.first { url.endsWith(it) }}").apply { asFile() }
if (file.exists()) return@async
val client = HttpClient(CIO) {
install(UserAgent) { agent = Constants.USER_AGENT }
}
val response: HttpResponse = client.get(url)
if (response.status == HttpStatusCode.OK) file.writeBytes(response.body())
return@async
} catch (e: Throwable) {
Log.e("Failed to download fonts ($name from $url)", e)
}
} }
}.awaitAll() }
try {
fontDef.main.keys.map { name ->
async {
val url = fontDef.main.getValue(name)
try {
val extension = FILE_EXTENSIONS.firstOrNull { url.substringBefore('?').endsWith(it) }
?: FILE_EXTENSIONS[0]
val file = File(fontsDir, "$name$extension").apply { asFile() }
if (file.exists()) return@async
Log.i("Downloading $name from $url")
val response: HttpResponse = client.get(url)
if (response.status == HttpStatusCode.OK) {
file.writeBytes(response.body())
} else {
Log.e("Failed to download fonts ($name from $url): HTTP ${response.status}")
}
} catch (e: Throwable) {
Log.e("Failed to download fonts ($name from $url)", e)
}
}
}.awaitAll()
} finally {
client.close()
}
} }
} }

View file

@ -1,11 +1,11 @@
package ShiggyXposed.xposed.modules.appearance package GoonXposed.xposed.modules.appearance
import android.R.color import android.R.color
import android.app.AndroidAppHelper
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import ShiggyXposed.xposed.Module import de.robv.android.xposed.XposedHelpers
import GoonXposed.xposed.Module
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -13,8 +13,13 @@ object SysColorsModule : Module() {
private lateinit var context: WeakReference<Context> private lateinit var context: WeakReference<Context>
private fun isSupported() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S private fun isSupported() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
@Deprecated("This method is deprecated in the parent class")
override fun buildPayload(builder: JsonObjectBuilder) { override fun buildPayload(builder: JsonObjectBuilder) {
context = WeakReference(AndroidAppHelper.currentApplication()) context = WeakReference(runCatching {
XposedHelpers.callStaticMethod(
XposedHelpers.findClass("android.app.ActivityThread", null), "currentApplication"
) as Context
}.getOrNull())
val accents = arrayOf("accent1", "accent2", "accent3", "neutral1", "neutral2") val accents = arrayOf("accent1", "accent2", "accent3", "neutral1", "neutral2")
val shades = arrayOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000) val shades = arrayOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
@ -37,7 +42,8 @@ object SysColorsModule : Module() {
} }
private fun convertToColor(id: Int): String { private fun convertToColor(id: Int): String {
val clr = if (isSupported()) ContextCompat.getColor(context.get()!!, id) else 0 val ctx = context.get()
val clr = if (isSupported() && ctx != null) ContextCompat.getColor(ctx, id) else 0
return String.format("#%06X", 0xFFFFFF and clr) return String.format("#%06X", 0xFFFFFF and clr)
} }
} }

View file

@ -1,12 +1,16 @@
package ShiggyXposed.xposed.modules.appearance package GoonXposed.xposed.modules.appearance
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Constants
import ShiggyXposed.xposed.Module import GoonXposed.xposed.MethodHookBuilder
import ShiggyXposed.xposed.Utils.Companion.JSON import GoonXposed.xposed.Module
import GoonXposed.xposed.Utils.Companion.JSON
import GoonXposed.xposed.asFile
import GoonXposed.xposed.hook
import GoonXposed.xposed.method
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonObjectBuilder import kotlinx.serialization.json.JsonObjectBuilder
@ -42,7 +46,7 @@ object ThemesModule : Module() {
private const val THEME_FILE = "current-theme.json" private const val THEME_FILE = "current-theme.json"
@Deprecated("This method is deprecated in the parent class")
@ExperimentalSerializationApi @ExperimentalSerializationApi
override fun buildPayload(builder: JsonObjectBuilder) { override fun buildPayload(builder: JsonObjectBuilder) {
builder.apply { builder.apply {
@ -81,10 +85,20 @@ object ThemesModule : Module() {
} }
fun hookTheme() { fun hookTheme() {
val themeManager = param.classLoader.loadClass("com.discord.theme.utils.ColorUtilsKt") try {
val darkTheme = param.classLoader.loadClass("com.discord.theme.DarkerTheme") val themeManager = param.classLoader.loadClass("com.discord.theme.utils.ColorUtilsKt")
val lightTheme = param.classLoader.loadClass("com.discord.theme.LightTheme") val darkTheme = param.classLoader.loadClass("com.discord.theme.DarkerTheme")
val lightTheme = param.classLoader.loadClass("com.discord.theme.LightTheme")
hookThemeInternal(themeManager, darkTheme, lightTheme)
} catch (e: Throwable) {
GoonXposed.xposed.Utils.Log.e("Failed to hook theme: ${e.message}")
}
}
private fun hookThemeInternal(
themeManager: Class<*>, darkTheme: Class<*>, lightTheme: Class<*>
) {
val theme = this.theme ?: return val theme = this.theme ?: return
// Apply rawColors // Apply rawColors
@ -106,42 +120,53 @@ object ThemesModule : Module() {
// If there's any rawColors value, hook the color getter // If there's any rawColors value, hook the color getter
if (!theme.data.rawColors.isNullOrEmpty()) { if (!theme.data.rawColors.isNullOrEmpty()) {
val getColorCompat = themeManager.getDeclaredMethod( try {
"getColorCompat", val getColorCompat = themeManager.getDeclaredMethod(
Resources::class.java, "getColorCompat",
Int::class.javaPrimitiveType, Resources::class.java,
Resources.Theme::class.java, Int::class.javaPrimitiveType,
) Resources.Theme::class.java,
)
val getColorCompatLegacy = themeManager.getDeclaredMethod( val getColorCompatLegacy = themeManager.getDeclaredMethod(
"getColorCompat", Context::class.java, Int::class.javaPrimitiveType "getColorCompat", Context::class.java, Int::class.javaPrimitiveType
) )
val patch = MethodHookBuilder().run { val patch = MethodHookBuilder().run {
before { before {
val arg1 = args[0] try {
val resources = if (arg1 is Context) arg1.resources else (arg1 as Resources) val arg1 = args[0]
val name = resources.getResourceEntryName(args[1] as Int) val resources = if (arg1 is Context) arg1.resources else (arg1 as Resources)
val name = resources.getResourceEntryName(args[1] as Int)
if (rawColorMap[name] != null) result = rawColorMap[name] if (rawColorMap[name] != null) result = rawColorMap[name]
} catch (_: Throwable) {
}
}
build()
} }
build() getColorCompat.hook(patch)
getColorCompatLegacy.hook(patch)
} catch (e: Throwable) {
GoonXposed.xposed.Utils.Log.e("Failed to hook getColorCompat: ${e.message}")
} }
getColorCompat.hook(patch)
getColorCompatLegacy.hook(patch)
} }
} }
// Parse HEX colour string to INT. Takes "#RRGGBBAA" or "#RRGGBB" // Parse HEX colour string to INT. Takes "#RRGGBBAA" or "#RRGGBB"
private fun hexStringToColorInt(hexString: String): Int { private fun hexStringToColorInt(hexString: String): Int {
return if (hexString.length == 9) { return try {
// Rearrange RRGGBBAA -> AARRGGBB so parseColor() is happy if (hexString.length == 9) {
val alpha = hexString.substring(7, 9) // Rearrange RRGGBBAA -> AARRGGBB so parseColor() is happy
val rrggbb = hexString.substring(1, 7) val alpha = hexString.substring(7, 9)
"#$alpha$rrggbb".toColorInt() val rrggbb = hexString.substring(1, 7)
} else hexString.toColorInt() "#$alpha$rrggbb".toColorInt()
} else hexString.toColorInt()
} catch (_: Throwable) {
0
}
} }
private fun hookThemeMethod(themeClass: Class<*>, methodName: String, themeValue: Int) { private fun hookThemeMethod(themeClass: Class<*>, methodName: String, themeValue: Int) {

View file

@ -1,4 +1,4 @@
package ShiggyXposed.xposed.modules.bridge package GoonXposed.xposed.modules.bridge
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
@ -7,9 +7,9 @@ import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.widget.Toast import android.widget.Toast
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils import GoonXposed.xposed.Utils
import ShiggyXposed.xposed.Utils.Companion.reloadApp import GoonXposed.xposed.getAppInfo
import java.io.File import java.io.File
object AdditionalBridgeMethodsModule : Module() { object AdditionalBridgeMethodsModule : Module() {
@ -48,11 +48,6 @@ object AdditionalBridgeMethodsModule : Module() {
file.writeText(contents as String) file.writeText(contents as String)
} }
BridgeModule.registerMethod("Shiggy.app.reload") {
reloadApp()
null
}
} }
override fun onActivity(activity: Activity) = with(activity) { override fun onActivity(activity: Activity) = with(activity) {
@ -65,10 +60,10 @@ object AdditionalBridgeMethodsModule : Module() {
val clip = ClipData.newPlainText("Stack Trace", errorString) val clip = ClipData.newPlainText("Stack Trace", errorString)
AlertDialog.Builder(this) AlertDialog.Builder(this)
.setTitle("ShiggyCord Error") .setTitle("GoonCord Error")
.setMessage( .setMessage(
""" """
ShiggyCord: $version GoonCord: $version
${app.name}: ${app.version} (${app.versionCode}) ${app.name}: ${app.version} (${app.versionCode})
Device: ${Build.MANUFACTURER} ${Build.MODEL} Device: ${Build.MANUFACTURER} ${Build.MODEL}

View file

@ -1,10 +1,12 @@
package ShiggyXposed.xposed.modules.bridge package GoonXposed.xposed.modules.bridge
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.BuildConfig import GoonXposed.xposed.BuildConfig
import ShiggyXposed.xposed.Constants import GoonXposed.xposed.Constants
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import GoonXposed.xposed.hookMethod
import GoonXposed.xposed.method
import java.lang.reflect.Method import java.lang.reflect.Method
/** /**

View file

@ -1,9 +1,11 @@
package ShiggyXposed.xposed.modules.no_track package GoonXposed.xposed.modules.no_track
import android.content.Context import android.content.Context
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import GoonXposed.xposed.hookMethod
import GoonXposed.xposed.safeLoadClass
/** /**
* Hooks Discord's crash reporting to disable Sentry initialization. * Hooks Discord's crash reporting to disable Sentry initialization.

View file

@ -1,9 +1,11 @@
package ShiggyXposed.xposed.modules.no_track package GoonXposed.xposed.modules.no_track
import android.content.Context import android.content.Context
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
import ShiggyXposed.xposed.Module import GoonXposed.xposed.Module
import ShiggyXposed.xposed.Utils.Log import GoonXposed.xposed.Utils.Log
import GoonXposed.xposed.hookMethod
import GoonXposed.xposed.safeLoadClass
/** /**
* Hooks Discord's deep links tracking to disable AppsFlyer initialization. * Hooks Discord's deep links tracking to disable AppsFlyer initialization.

View file

@ -1,3 +1,3 @@
<resources> <resources>
<string name="app_name">ShiggyXposed</string> <string name="app_name">GoonXposed</string>
</resources> </resources>