Compare commits

...

248 commits
v1.1.0 ... main

Author SHA1 Message Date
OTKUSteyler
2cc79c59d0
Update InjectShiggyXposedStep.kt
Some checks failed
Build Debug App / build (push) Failing after 7m12s
2026-09-07 05:40:27 +02:00
OTKUSteyler
3ba2f9a460
Merge branch 'kmmiio99o:main' into main 2026-06-09 13:55:29 +02:00
kmmiio99o
0045d3b2a4
chore: bump version 2026-06-09 11:27:20 +00:00
kmmiio99o
71fab34c98
fix: use locale-independent formatting for LSPatch output filename (#4)
Fixes installation failures on non-Latin locales by ensuring the LSPatch
output filename lookup uses Latin numerals regardless of device locale.

LSPatch uses String.format(Locale.getDefault(), ...) which produces
locale-specific numerals (e.g., Arabic numerals on Arabic locales),
but the filename lookup was using hardcoded Latin numerals, causing
a mismatch that resulted in "Invalid package" errors.

Fixes #XXXX
2026-06-09 11:22:11 +00:00
OTKUSteyler
fdf93c7b1e
Update README.md 2026-05-22 21:51:05 +02:00
OTKUSteyler
460375e4ac
Update README.md 2026-05-22 21:50:25 +02:00
OTKUSteyler
28fe88c157 Merge remote-tracking branch 'upstream/main' 2026-05-08 00:02:56 +02:00
kmmiio99o
eaad9755ea
chore: bump to 1.1.2 2026-05-07 16:02:23 +02:00
kmmiio99o
50d58dc4e1
feat: use JingMatrix lspatch 2026-05-07 16:01:23 +02:00
OTKUSteyler
62c5659245
Merge branch 'kmmiio99o:main' into main 2026-04-28 12:42:55 +02:00
CatPieLeaf
7411ceb7a7
chore: update LSPatch and use JingMatrix fork (#3) 2026-04-28 11:51:17 +02:00
OTKUSteyler
ac57f05cae
Merge branch 'kmmiio99o:main' into main 2026-04-02 06:28:15 +02:00
мекатів
dcc33736a3
feat(manifestpatcher): allow connecting over http (#2)
Co-authored-by: meqativ <meqativ@users.noreply.github.com>
2026-04-01 23:47:23 +02:00
OTKUSteyler
35dca04b37
Update ic_discord_aliucord.xml 2026-03-26 09:50:04 +01:00
OTKUSteyler
748bb9dc59
Update colors.xml 2026-03-26 07:44:12 +01:00
j
1fa78ab647
proper icon referencing 2026-03-04 10:23:30 +01:00
J
6a3c90d12b fix(icon/anydpi-v26): nuked the wrong icons, replaced with right icons 2026-03-02 17:25:42 +01:00
OTKUSteyler
a00a6fdf66
Update ic_discord_aliucord.xml 2026-03-02 16:39:17 +01:00
OTKUSteyler
17b40741ea
Update ic_launcher.xml 2026-03-02 01:41:36 +01:00
OTKUSteyler
5c17dc3f9d
Update colors.xml 2026-03-02 01:30:32 +01:00
OTKUSteyler
0cd04a473a
Delete app/src/main/res/ic_launcher_round.png 2026-03-02 01:07:26 +01:00
OTKUSteyler
f234785571
Delete app/src/main/res/ic_launcher.png 2026-03-02 01:07:18 +01:00
OTKUSteyler
98625b22b8
Update colors.xml 2026-03-01 22:35:35 +01:00
OTKUSteyler
15a81b53ac
Update strings.xml 2026-03-01 22:32:15 +01:00
OTKUSteyler
3c8f78ef68
Update ic_launcher_background.xml 2026-03-01 22:27:59 +01:00
OTKUSteyler
1725bb6f0d
Update colors.xml 2026-03-01 21:53:23 +01:00
OTKUSteyler
2b62ed13a3
Update colors.xml 2026-03-01 21:43:53 +01:00
OTKUSteyler
d414b9c20a
Update fun facts in strings.xml 2026-03-01 21:41:35 +01:00
OTKUSteyler
e331dbb030
Update strings.xml 2026-03-01 21:39:35 +01:00
OTKUSteyler
ecd5c55008
Add files via upload 2026-02-20 18:01:33 +01:00
OTKUSteyler
7b82e406a4
Add files via upload 2026-02-20 18:00:08 +01:00
OTKUSteyler
eee219a4d1
Add files via upload 2026-02-20 17:59:58 +01:00
OTKUSteyler
012ece1855
Add files via upload 2026-02-20 17:59:45 +01:00
OTKUSteyler
2b12b2fb4e
Add files via upload 2026-02-20 17:59:30 +01:00
OTKUSteyler
0c58003936 Add files via upload 2026-02-20 17:59:12 +01:00
OTKUSteyler
6a5114cad0
Add files via upload 2026-02-20 17:59:01 +01:00
OTKUSteyler
17cd3d552e
Update ic_rounded_shiggy.xml 2026-02-20 06:56:39 +01:00
OTKUSteyler
9aefa5fed7
Update ic_rounded_shiggy.xml 2026-02-19 22:57:24 +01:00
OTKUSteyler
5df4a74536
Add files via upload 2026-02-19 20:34:00 +01:00
OTKUSteyler
94720320d8
Add files via upload 2026-02-19 20:22:53 +01:00
OTKUSteyler
3f29feecec
Add files via upload 2026-02-19 20:22:38 +01:00
OTKUSteyler
3529f5f7c1
Add files via upload 2026-02-19 20:22:21 +01:00
OTKUSteyler
ad6e5eb850
Add files via upload 2026-02-19 20:21:48 +01:00
OTKUSteyler
546d97844e
Add files via upload 2026-02-19 20:21:06 +01:00
OTKUSteyler
d0aff56a91
Add files via upload 2026-02-19 20:10:42 +01:00
OTKUSteyler
665b60654e
Add files via upload 2026-02-19 20:10:34 +01:00
OTKUSteyler
6eebcdb494
Add files via upload 2026-02-19 20:10:26 +01:00
OTKUSteyler
f3f352977e
Add files via upload 2026-02-19 20:10:13 +01:00
OTKUSteyler
e0aac86ec2
Add files via upload 2026-02-19 20:09:29 +01:00
OTKUSteyler
1b29c8070b
Update ic_discord.xml 2026-02-17 01:06:53 +01:00
OTKUSteyler
f60c24a259
Update ic_discord_aliucord.xml 2026-02-17 01:06:07 +01:00
OTKUSteyler
bcf39e1e65
Update ic_discord.xml 2026-02-17 01:03:33 +01:00
OTKUSteyler
1dea909ef5
Update ic_rounded_shiggy.xml 2026-02-17 00:12:38 +01:00
OTKUSteyler
b90183d4a6
Update ic_rounded_shiggy.xml 2026-02-17 00:10:40 +01:00
OTKUSteyler
ca59a08cc2
Update ic_rounded_shiggy.xml 2026-02-17 00:08:57 +01:00
OTKUSteyler
28dc73b7ae
Update ic_rounded_shiggy.xml 2026-02-17 00:06:34 +01:00
OTKUSteyler
84677d92c2
Update ic_rounded_shiggy.xml 2026-02-17 00:05:14 +01:00
OTKUSteyler
57f7d8b3dc
Update ic_rounded_shiggy.xml 2026-02-17 00:03:07 +01:00
OTKUSteyler
3c1c423283
Update ic_rounded_shiggy.xml 2026-02-17 00:02:46 +01:00
OTKUSteyler
aa4a3a6847
Update ic_discord.xml 2026-02-16 23:47:00 +01:00
OTKUSteyler
fedb711333
Update ic_rounded_shiggy.xml 2026-02-16 23:43:46 +01:00
OTKUSteyler
4b7b0009fa
Update ic_discord.xml 2026-02-16 23:42:26 +01:00
OTKUSteyler
b033d53c5b
Update ic_discord.xml 2026-02-16 23:40:51 +01:00
OTKUSteyler
cb3021e2a2
Update ic_rounded_shiggy.xml 2026-02-15 23:36:53 +01:00
OTKUSteyler
82e69d5ab1
Update ic_rounded_shiggy.xml 2026-02-15 23:30:42 +01:00
OTKUSteyler
e499c7d228
Update ic_rounded_shiggy.xml 2026-02-15 23:30:13 +01:00
OTKUSteyler
2759b71df1
Update ic_discord.xml 2026-02-15 23:27:30 +01:00
OTKUSteyler
6663e4a912
Update ic_rounded_shiggy.xml 2026-02-15 23:26:53 +01:00
OTKUSteyler
1e4b846dbd
Update ic_rounded_shiggy.xml 2026-02-14 17:22:17 +01:00
OTKUSteyler
d6fd188dce
Update ic_rounded_shiggy.xml 2026-02-12 20:13:14 +01:00
OTKUSteyler
c5d9dc9821
Update ic_rounded_shiggy.xml 2026-02-11 23:16:00 +01:00
OTKUSteyler
45f14b92fe
Update ic_rounded_shiggy.xml 2026-02-11 23:01:32 +01:00
OTKUSteyler
79a215d318
Merge branch 'kmmiio99o:main' into main 2026-01-16 21:29:00 +00:00
kmmiio99o
8cf989a239
feat: Add basic implementation of Amoled mode in the manager and fix
some misspells

TODO:
- Fix instance card to also use Amoled when needed
2026-01-16 20:44:29 +01:00
OTKUSteyler
d07c8e953d
Merge branch 'kmmiio99o:main' into main 2026-01-10 16:32:35 +00:00
kmmiio99o
3c14917b2f
bump to 10_11_01 2026-01-10 17:21:38 +01:00
kmmiio99o
48b5e39f3a
feat: possible fix rate limiting and github being blocked in some
countries?
2026-01-10 17:21:14 +01:00
OTKUSteyler
eb41f0ec8e
Update DownloadShiggyXposedStep.kt 2025-11-26 09:54:16 +01:00
OTKUSteyler
5dcee025b6
Update README.md 2025-11-23 16:26:35 +01:00
kmmiio99o
49392ab273 Fix: Fix Manager and About Manager Page
Some checks failed
Build Debug App / build (push) Failing after 5s
Build & Publish Release App / publish (push) Failing after 5s
- Updates the file name to goon.json, consistent with the GoonCord
rebrand - Fixes the metadata reading code to use the correct name -
Update references in `InstallMetadata.kt` and `SaveMetadataStep.kt`. -
Replace "ShiggyCord" with "GoonCord" in `AboutModel.kt`. - Rename
`ContributorListItem` to `RegularContributorListItem` - Add a new
"LeadContributorItem" composable. - Rename `shiggyXposedVersion` to
`goonXposedVersion`. - Fix version up to date comparison
2025-11-23 14:52:24 +01:00
OTKUSteyler
ba79a54b83
Update HomeModel.kt 2025-11-23 11:16:29 +01:00
OTKUSteyler
96400eb22c
Delete app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins directory 2025-11-23 11:14:09 +01:00
OTKUSteyler
2d213f46e8
Update ContributorListItem.kt 2025-11-22 22:29:03 +01:00
OTKUSteyler
a51e82c077
Update AboutModel.kt 2025-11-22 22:26:03 +01:00
OTKUSteyler
a1d70359a2
Delete app/src/main/kotlin/com/aliucord/manager/network/models/Developers.kt 2025-11-22 22:22:45 +01:00
OTKUSteyler
4f96d33abd Merge remote-tracking branch 'upstream/main' 2025-11-22 21:58:40 +01:00
OTKUSteyler
af71c66820
Rename ContributorListItem.kt. to ContributorListItem.kt 2025-11-22 08:41:38 +01:00
OTKUSteyler
54312834b8
Rename ContributorListItem.kt.txt to ContributorListItem.kt. 2025-11-22 08:41:28 +01:00
OTKUSteyler
b99015fa99
Add files via upload 2025-11-22 08:40:57 +01:00
OTKUSteyler
87190ad7aa
Update AboutModel.kt 2025-11-22 08:39:23 +01:00
OTKUSteyler
13ec434a2d
Update AboutScreen.kt 2025-11-22 08:32:27 +01:00
OTKUSteyler
2ddd8b5964
Update Developers.kt 2025-11-22 08:27:38 +01:00
OTKUSteyler
974119863e
Update Developers.kt 2025-11-22 08:23:19 +01:00
OTKUSteyler
9783e33885
Rename Contributors.kt to Developers.kt 2025-11-22 01:37:10 +01:00
OTKUSteyler
855869f2d9
Update Developers.kt 2025-11-22 01:34:10 +01:00
OTKUSteyler
a6ab500b8a
Rename Contributors.kt to Developers.kt 2025-11-22 01:31:14 +01:00
OTKUSteyler
48de3a521e
Rename Developer.kt to Contributors.kt 2025-11-22 01:09:45 +01:00
OTKUSteyler
c1cf8365ff
Add files via upload 2025-11-21 23:42:44 +01:00
OTKUSteyler
38dec41e9e
Update HomeScreen.kt 2025-11-21 23:40:44 +01:00
OTKUSteyler
c41083a237
Update HomeScreenLoadedPreview.kt 2025-11-21 23:38:56 +01:00
OTKUSteyler
72b669d349
Update PathManager.kt 2025-11-21 23:36:23 +01:00
OTKUSteyler
d8e7984302
Update and rename Contributor.kt to Developer.kt 2025-11-21 23:35:25 +01:00
OTKUSteyler
3952c72540
Update ManagerApplication.kt 2025-11-21 23:32:54 +01:00
OTKUSteyler
e76bd45ef6
Update AboutModel.kt 2025-11-21 23:31:38 +01:00
OTKUSteyler
c67a6a116f
Update LeadContributor.kt 2025-11-21 23:30:28 +01:00
OTKUSteyler
7680cb7b3b
Update AboutModel.kt 2025-11-21 23:29:56 +01:00
OTKUSteyler
cbe6392946
Update AboutScreenState.kt 2025-11-21 23:28:20 +01:00
OTKUSteyler
2142ba837e
Update AboutScreen.kt 2025-11-21 23:27:55 +01:00
OTKUSteyler
de1cbb9009
Update InstalledItemCard.kt 2025-11-21 23:26:35 +01:00
OTKUSteyler
c5e3bd7c6b
Update HomeModel.kt 2025-11-21 23:25:30 +01:00
OTKUSteyler
2e8b3b07d8
Update build.gradle.kts 2025-11-21 23:18:10 +01:00
kmmiio99o
47737d1c19 `` feat: Bump app version to 1.1.1 `` - Fix: Use correct version name
- Remove: Unused code, plugins screen, and contributor model - Refactor:
Use new `Developer` model - Feat: Update about screen to display
developer list - Feat: Add github icon to plugin card - Chore: Fix
installer icon
2025-11-21 22:27:54 +01:00
OTKUSteyler
87d5c1efce
Update AboutScreen.kt 2025-11-20 13:27:41 +01:00
OTKUSteyler
37e4553df5
Update AboutScreen.kt 2025-11-20 13:26:03 +01:00
OTKUSteyler
383af45097
Update AboutScreen.kt 2025-11-20 13:21:09 +01:00
OTKUSteyler
0db19a65fe
Update AboutScreen.kt 2025-11-20 09:56:43 +01:00
OTKUSteyler
9cdb4e78e7
Update AboutScreen.kt 2025-11-19 23:28:58 +01:00
OTKUSteyler
e9bd7b6253
Update strings.xml 2025-11-19 23:28:32 +01:00
OTKUSteyler
8d2edb6f58
Update strings.xml 2025-11-19 23:26:38 +01:00
OTKUSteyler
e319e2b0f4
Update AboutScreen.kt 2025-11-19 23:22:40 +01:00
OTKUSteyler
9f87a3dff6
Update strings.xml 2025-11-19 23:18:21 +01:00
OTKUSteyler
8c2777e713
Update strings.xml 2025-11-19 23:16:25 +01:00
OTKUSteyler
a4cb364a24
Update AboutScreen.kt 2025-11-19 23:08:50 +01:00
OTKUSteyler
321b3ad3e0
Update AboutScreen.kt 2025-11-19 23:06:27 +01:00
OTKUSteyler
9185bfa37a
Update AboutScreen.kt 2025-11-19 23:03:11 +01:00
OTKUSteyler
8d4a93fc38
Update AboutScreen.kt 2025-11-19 23:00:32 +01:00
OTKUSteyler
770d624256
Update AboutScreen.kt 2025-11-19 22:56:21 +01:00
OTKUSteyler
aff5822da1
Update AboutScreen.kt 2025-11-19 22:52:28 +01:00
OTKUSteyler
ff545d86fc
Update AboutScreen.kt 2025-11-19 22:45:52 +01:00
OTKUSteyler
1e815a3991
Update AboutScreen.kt 2025-11-19 22:43:12 +01:00
OTKUSteyler
03300a8fbb
Update AboutScreen.kt 2025-11-19 22:36:07 +01:00
OTKUSteyler
5e961e4ec7
Update AboutScreen.kt 2025-11-19 22:34:56 +01:00
OTKUSteyler
8d2662f919
Update AboutModel.kt 2025-11-19 22:28:06 +01:00
OTKUSteyler
69829fa3cf
Update README.md 2025-11-11 09:45:17 +01:00
kmmiio99o
840d6232e3 Describe my changes
Some checks failed
Build Debug App / build (push) Failing after 5s
Build & Publish Release App / publish (push) Failing after 5s
2025-11-11 01:21:52 +01:00
OTKUSteyler
bc7cb499ef
Update README.md 2025-11-10 23:30:31 +01:00
OTKUSteyler
bbfc129d1e
Merge branch 'kmmiio99o:main' into main
Some checks failed
Build Debug App / build (push) Failing after 5s
Build & Publish Release App / publish (push) Failing after 5s
2025-11-10 23:22:51 +01:00
OTKUSteyler
3576f16ad4
Update README.md 2025-11-10 23:20:12 +01:00
OTKUSteyler
f6e5f7283d
Update Contributors.kt 2025-11-10 23:12:30 +01:00
OTKUSteyler
162627d571
Update AndroidDownloadManager.kt 2025-11-10 23:11:48 +01:00
OTKUSteyler
3394490dd9
Update TextBannerPreview.kt 2025-11-10 23:09:41 +01:00
OTKUSteyler
828a0c9696
Update AboutScreen.kt 2025-11-10 23:09:08 +01:00
OTKUSteyler
09fcea6f1b
Update LogAppBar.kt 2025-11-10 23:07:06 +01:00
OTKUSteyler
e861642964
Update LogScreen.kt 2025-11-10 23:06:40 +01:00
OTKUSteyler
79025f0e97
Update LogScreenModel.kt 2025-11-10 23:06:24 +01:00
OTKUSteyler
61438c48a5
Update UpdaterDialog.kt 2025-11-10 23:04:33 +01:00
OTKUSteyler
91fa48d134
Update UpdaterViewModel.kt 2025-11-10 23:04:17 +01:00
OTKUSteyler
8c26fe34b7
Update RGBTextField.kt 2025-11-10 23:01:49 +01:00
OTKUSteyler
4f8fc65996
Update IconOptionsAppBar.kt 2025-11-10 23:01:30 +01:00
OTKUSteyler
467a781efd
Update IconOptionsModel.kt 2025-11-10 23:01:01 +01:00
OTKUSteyler
e5ddf7df90
Update IconOptionsScreen.kt 2025-11-10 23:00:34 +01:00
OTKUSteyler
2c8495a219
Update InstalledItemCard.kt 2025-11-10 22:47:12 +01:00
OTKUSteyler
75730992f8
Update InstallButton.kt 2025-11-10 22:46:55 +01:00
OTKUSteyler
f3114a72be
Update HomeAppBar.kt 2025-11-10 22:46:38 +01:00
OTKUSteyler
28e8e7c708
Update HomeScreen.kt 2025-11-10 22:46:17 +01:00
OTKUSteyler
0b93228fcc
Update HomeModel.kt 2025-11-10 22:45:43 +01:00
OTKUSteyler
d5a6647f01
Update DeleteLogsDialog.kt 2025-11-10 22:44:10 +01:00
OTKUSteyler
80cb5e46c7
Update LogEntryCard.kt 2025-11-10 22:43:42 +01:00
OTKUSteyler
74df4c8446
Update LogsListAppBar.kt 2025-11-10 22:43:22 +01:00
OTKUSteyler
70108328d1
Update LogsNone.kt 2025-11-10 22:42:59 +01:00
OTKUSteyler
8d48dc2e0d
Update LogsListScreenModel.kt 2025-11-10 22:42:28 +01:00
OTKUSteyler
0d7f730841
Update PatchingAppBar.kt 2025-11-10 22:42:00 +01:00
OTKUSteyler
091d241d13
Update StepGroupCard.kt 2025-11-10 22:41:42 +01:00
OTKUSteyler
1d7293f1dd
Update StepStateIcon.kt 2025-11-10 22:41:16 +01:00
OTKUSteyler
7632ac1fa8
Update FunFact.kt 2025-11-10 22:40:48 +01:00
OTKUSteyler
7e7cd04527
Update PatchingScreen.kt 2025-11-10 22:40:28 +01:00
OTKUSteyler
40fccfd0f9
Update PatchingScreenModel.kt 2025-11-10 22:39:59 +01:00
OTKUSteyler
269f7043c4
Update PackageNameStateLabel.kt 2025-11-10 22:39:08 +01:00
OTKUSteyler
f0a4045642
Update PatchOptionsAppBar.kt 2025-11-10 22:38:51 +01:00
OTKUSteyler
3c5a7087f2
Update PatchOptionsScreen.kt 2025-11-10 22:38:21 +01:00
OTKUSteyler
c4c20aeeaa
Update RootDetectedDialog.kt 2025-11-10 22:24:06 +01:00
OTKUSteyler
c2a8cc9f8a
Update InstallerDialog.kt 2025-11-10 22:23:44 +01:00
OTKUSteyler
3aae7baef5
Update ShizukuInfoDialog.kt 2025-11-10 22:23:21 +01:00
OTKUSteyler
0e5a29a862
Update ThemeDialog.kt 2025-11-10 22:22:57 +01:00
OTKUSteyler
4e33b98130
Update SettingsModel.kt 2025-11-10 22:22:33 +01:00
OTKUSteyler
03f8d320d3
Update SettingsScreen.kt 2025-11-10 22:21:58 +01:00
kmmiio99o
97cf2a9b6c "Try" to fix **Invalid semver string 1.1.0.1**
- Try to fix **Invalid semver string 1.1.0.1** - Patch Unknown
permissions menu, so when shizuku or root are used, it would not show up
- Try to fix signing
2025-11-10 22:15:24 +01:00
OTKUSteyler
705bea72ed
Update UninstallPluginDialog.kt 2025-11-10 22:14:13 +01:00
OTKUSteyler
dea0483ce6
Update PluginCard.kt 2025-11-10 22:13:54 +01:00
OTKUSteyler
e425354833
Update PluginSearch.kt 2025-11-10 22:13:36 +01:00
OTKUSteyler
68b808b98f
Update Changelog.kt 2025-11-10 22:13:18 +01:00
OTKUSteyler
5907dd50b2
Update PluginsError.kt 2025-11-10 22:12:44 +01:00
OTKUSteyler
762c0a0043
Update PluginsNone.kt 2025-11-10 22:12:25 +01:00
OTKUSteyler
6b5ef4ae38
Update PluginsModel.kt 2025-11-10 22:11:35 +01:00
OTKUSteyler
a7f0ab2aa6
Update PluginsScreen.kt 2025-11-10 22:11:02 +01:00
OTKUSteyler
2c248a8520
Update InstallLogManager.kt 2025-11-10 22:05:58 +01:00
OTKUSteyler
395a9ca595
Update NetworkWarningDialog.kt 2025-11-10 21:57:42 +01:00
OTKUSteyler
10e9c66e77
Update StoragePermissionsDialog.kt 2025-11-10 21:57:20 +01:00
OTKUSteyler
3a1122ebc3
Update PlayProtectDialog.kt 2025-11-10 21:57:02 +01:00
OTKUSteyler
32772a10d8
Update UnknownSourcesPermissionDialog.kt 2025-11-10 21:56:46 +01:00
OTKUSteyler
62be760583
Update InstallerAbortDialog.kt 2025-11-10 21:56:26 +01:00
OTKUSteyler
c20c2b88ad
Update CustomComponentVersionPicker.kt 2025-11-10 21:56:11 +01:00
OTKUSteyler
a3292620c8
Update ProjectHeader.kt 2025-11-10 21:55:33 +01:00
OTKUSteyler
2f0deb09bd
Update ResetToDefaultButton.kt 2025-11-10 21:55:14 +01:00
OTKUSteyler
a921d97452
Update LoadFailure.kt 2025-11-10 21:54:47 +01:00
OTKUSteyler
de9ecb42cb
Update CustomDiscordAppIcon.kt 2025-11-10 21:54:25 +01:00
OTKUSteyler
9c9d45e734
Update BackButton.kt 2025-11-10 21:54:10 +01:00
OTKUSteyler
e65067d300
Update Signer.kt 2025-11-10 21:53:22 +01:00
OTKUSteyler
c251ad69c2
Update HttpService.kt 2025-11-10 21:52:39 +01:00
OTKUSteyler
5b97dccb2e
Update KtorDownloadManager.kt 2025-11-10 21:51:21 +01:00
OTKUSteyler
ec4f077722
Update Http.kt 2025-11-10 21:50:13 +01:00
OTKUSteyler
366c772bc8
Update build.gradle.kts 2025-11-10 21:43:44 +01:00
OTKUSteyler
aef3873bbd
Update build.gradle.kts 2025-11-10 21:43:12 +01:00
OTKUSteyler
07473077f0
Update Context.kt 2025-11-10 21:39:56 +01:00
OTKUSteyler
b82334a121
Update InstallNotifications.kt 2025-11-10 21:38:42 +01:00
OTKUSteyler
1c9fd9cac0
Update DiscordVersion.kt 2025-11-10 21:38:17 +01:00
OTKUSteyler
1710bddad4
Update IconOptionsScreenPreview.kt 2025-11-10 21:38:01 +01:00
OTKUSteyler
e4498c9f77
Update ShiggyGithubService.kt 2025-11-10 21:36:41 +01:00
OTKUSteyler
1e0834f682
Update DownloadStep.kt 2025-11-10 21:34:38 +01:00
OTKUSteyler
e2a1efbd4c
Update DownloadShiggyXposedStep.kt 2025-11-10 21:34:07 +01:00
OTKUSteyler
e887ae202e
Update DownloadPatchesStep.kt 2025-11-10 21:33:47 +01:00
OTKUSteyler
af7eaa2e45
Update DownloadKotlinStep.kt 2025-11-10 21:33:27 +01:00
OTKUSteyler
80e0dbf802
Update DownloadInjectorStep.kt 2025-11-10 21:33:13 +01:00
OTKUSteyler
cc4cd6333c
Update DownloadDiscordStep.kt 2025-11-10 21:32:53 +01:00
OTKUSteyler
8fd16ad03b
Update DownloadDiscordRNAResourcesStep.kt 2025-11-10 21:32:32 +01:00
OTKUSteyler
50de8f82e8
Update DownloadDiscordRNALibStep.kt 2025-11-10 21:32:16 +01:00
OTKUSteyler
0ded5d941e
Update DownloadDiscordRNALangStep.kt 2025-11-10 21:32:04 +01:00
OTKUSteyler
255c1713bd
Update DownloadDiscordRNABaseStep.kt 2025-11-10 21:31:50 +01:00
OTKUSteyler
ca19cbff65
Update DownloadAliuhookStep.kt 2025-11-10 21:31:31 +01:00
OTKUSteyler
c085ec10a3
Update CopyDependenciesStep.kt 2025-11-10 21:31:17 +01:00
OTKUSteyler
d5fae8be78
Update SigningStep.kt 2025-11-10 21:30:47 +01:00
OTKUSteyler
7e47c3090c
Update InstallStep.kt 2025-11-10 21:30:30 +01:00
OTKUSteyler
3e7e548e5d
Update InjectShiggyXposedStep.kt 2025-11-10 21:30:12 +01:00
OTKUSteyler
8688f68300
Update CleanupStep.kt 2025-11-10 21:29:46 +01:00
OTKUSteyler
ae70891761
Update AlignmentStep.kt 2025-11-10 21:29:30 +01:00
OTKUSteyler
7f4551d8f7
Update AddAliuhookLibsStep.kt 2025-11-10 21:29:09 +01:00
OTKUSteyler
ef0f321eb9
Update PatchIconsStep.kt 2025-11-10 21:28:45 +01:00
OTKUSteyler
2c191f710c
Update PatchManifestStep.kt 2025-11-10 21:28:21 +01:00
OTKUSteyler
0e95128735
Update ReorganizeDexStep.kt 2025-11-10 21:27:46 +01:00
OTKUSteyler
45a57e182d
Update SaveMetadataStep.kt 2025-11-10 21:26:44 +01:00
OTKUSteyler
3cc6f0d9bf
Update SmaliPatchStep.kt 2025-11-10 21:26:26 +01:00
OTKUSteyler
6371bcd356
Update DowngradeCheckStep.kt 2025-11-10 21:25:13 +01:00
OTKUSteyler
94351c2de7
Update FetchDiscordRNAStep.kt 2025-11-10 21:24:48 +01:00
OTKUSteyler
e209ad1863
Update FetchInfoStep.kt 2025-11-10 21:23:42 +01:00
OTKUSteyler
6a9d25f5d2
Update RestoreDownloadsStep.kt 2025-11-10 21:23:23 +01:00
OTKUSteyler
c28d379314
Update StepGroup.kt 2025-11-10 21:22:59 +01:00
OTKUSteyler
13d23fc2b9
Update StepRunner.kt 2025-11-10 21:21:56 +01:00
OTKUSteyler
7a52223e42
Update ThemeTypography.kt 2025-11-10 21:19:57 +01:00
OTKUSteyler
82d7517d56
Update Theme.kt 2025-11-10 21:19:29 +01:00
OTKUSteyler
0ade279070
Update PMResultReceiver.kt 2025-11-10 21:18:21 +01:00
OTKUSteyler
721b936486
Update PMIntentReceiver.kt 2025-11-10 21:17:53 +01:00
OTKUSteyler
63dd895588
Update PMInstallerError.kt 2025-11-10 21:17:33 +01:00
OTKUSteyler
2d3d52b405
Update PMInstaller.kt 2025-11-10 21:17:05 +01:00
OTKUSteyler
f162522a60
Update ShizukuIntentReceiver.kt 2025-11-10 21:15:02 +01:00
OTKUSteyler
c087f3718c
Update ShizukuInstaller.kt 2025-11-10 21:14:24 +01:00
OTKUSteyler
7e957c9624
Update UnknownInstallerError.kt 2025-11-10 21:13:33 +01:00
OTKUSteyler
b18fea83ed
Update MainActivity.kt 2025-11-10 21:12:22 +01:00
OTKUSteyler
4af5186cc0
Update strings.xml 2025-11-10 21:10:00 +01:00
157 changed files with 847 additions and 1629 deletions

View file

@ -26,7 +26,7 @@ Goon Manager makes installing and managing Discord mods simple and safe. It's bu
<p><strong>Download & run</strong> — get a released APK from Releases and install with:</p>
Get newest apk from [release list](https://github.com/OTKUSteyler/GoonManager/releases/tag/V1.0) and install it.
Get newest apk from [release list](https://github.com/OTKUSteyler/GoonManager/releases/tag/v1.1.3) and install it.
<p><strong>Build from source</strong> — clone and assemble:</p>
@ -127,3 +127,5 @@ Goon Manager is open source under the OSL License. See `LICENSE` for details.
<p align="center">
<strong>Made with ❤️ for the GoonCord community — keep it playful, keep it safe.</strong>
</p>
![OTKUSteyler](https://count.getloli.com/@OTKUSteyler?name=OTKUSteyler&theme=miku&padding=7&offset=0&align=top&scale=1&pixelated=1&darkmode=1)

View file

@ -20,13 +20,13 @@ val gitHasHasLocalChanges = providers.execIgnoreCode("git", "status", "-s").isNo
android {
namespace = "dev.shiggy.manager"
compileSdk = 36
compileSdk = 37
defaultConfig {
minSdk = 28
targetSdk = 36
versionCode = 10_10_00
versionName = "1.1.0"
targetSdk = 37
versionCode = 10_12_01
versionName = "1.1.2"
vectorDrawables {
useSupportLibrary = true
}

30
app/libs/convert-lspatch.sh Executable file
View file

@ -0,0 +1,30 @@
# Download LSPatch jar and convert it to an aar
# Jars cannot be used as a dependency without breaking R8 optimization
LSPATCH_URL="https://github.com/JingMatrix/LSPatch/releases/latest/download/lspatch.jar"
LSPATCH_FILE_NAME="lspatch"
function cleanup {
rm -rf $LSPATCH_FILE_NAME.jar META-INF AndroidManifest.xml classes.jar R.txt
}
cleanup
# download lspatch
curl -sSL -o $LSPATCH_FILE_NAME.jar $LSPATCH_URL
# prepare aar contents
unzip -q $LSPATCH_FILE_NAME.jar "META-INF/**"
mv $LSPATCH_FILE_NAME.jar classes.jar
touch R.txt
cat >AndroidManifest.xml <<EOF
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.lsposed.lspatch">
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="36" />
</manifest>
EOF
# add everything to aar
rm -f $LSPATCH_FILE_NAME.aar
zip -rq $LSPATCH_FILE_NAME.aar R.txt AndroidManifest.xml META-INF classes.jar
cleanup

Binary file not shown.

View file

@ -18,11 +18,11 @@
<application
android:name="com.aliucord.manager.ManagerApplication"
android:icon="@mipmap/ic_launcher"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:roundIcon="@drawable/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.NoActionBar"
>

View file

@ -24,7 +24,7 @@ import com.aliucord.manager.ui.screens.home.HomeScreen
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.widgets.updater.UpdaterDialog
import com.aliucord.manager.util.back
import dev.shiggy.manager.BuildConfig
import dev.goon.manager.BuildConfig
import org.koin.android.ext.android.inject
class MainActivity : ComponentActivity() {
@ -42,6 +42,7 @@ class MainActivity : ComponentActivity() {
ManagerTheme(
theme = preferences.theme,
dynamicColor = preferences.dynamicColor,
amoled = preferences.amoled,
) {
if (BuildConfig.RELEASE) {
UpdaterDialog()

View file

@ -17,7 +17,7 @@ import com.aliucord.manager.ui.screens.log.LogScreenModel
import com.aliucord.manager.ui.screens.logs.LogsListScreenModel
import com.aliucord.manager.ui.screens.patching.PatchingScreenModel
import com.aliucord.manager.ui.screens.patchopts.PatchOptionsModel
import com.aliucord.manager.ui.screens.plugins.PluginsModel
import com.aliucord.manager.ui.screens.settings.SettingsModel
import com.aliucord.manager.ui.widgets.updater.UpdaterViewModel
import com.aliucord.manager.installers.root.RootInstaller
@ -57,7 +57,7 @@ class ManagerApplication : Application() {
// UI Models
modules(module {
factory { HomeModel(get<Application>(), get<AliucordGithubService>(), get<AliucordMavenService>(), get<ShiggyGithubService>(), get<RNATrackerService>(), get<kotlinx.serialization.json.Json>(), get<com.aliucord.manager.manager.PreferencesManager>()) }
factoryOf(::PluginsModel)
factoryOf(::AboutModel)
factoryOf(::PatchingScreenModel)
factory { SettingsModel(get<Application>(), get<PathManager>(), get<PreferencesManager>(), get<InstallerManager>()) }

View file

@ -1,7 +1,7 @@
package com.aliucord.manager.di
import android.app.Application
import dev.shiggy.manager.BuildConfig
import dev.goon.manager.BuildConfig
import io.ktor.client.HttpClient
import io.ktor.client.call.HttpClientCall
import io.ktor.client.engine.okhttp.OkHttp

View file

@ -1,7 +1,7 @@
package com.aliucord.manager.installers
import android.content.Context
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.parcelize.Parcelize
@Parcelize

View file

@ -4,7 +4,7 @@ import android.app.Application
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.util.Log
import dev.shiggy.manager.BuildConfig
import dev.goon.manager.BuildConfig
import com.aliucord.manager.installers.Installer
import kotlinx.coroutines.suspendCancellableCoroutine
import java.io.File

View file

@ -4,7 +4,7 @@ import android.content.Context
import android.content.pm.PackageInstaller
import android.os.Parcelable
import com.aliucord.manager.installers.InstallerResult
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.parcelize.Parcelize
/**

View file

@ -7,7 +7,7 @@ import android.util.Log
import android.widget.Toast
import com.aliucord.manager.installers.InstallerResult
import com.aliucord.manager.installers.UnknownInstallerError
import dev.shiggy.manager.BuildConfig
import dev.goon.manager.BuildConfig
/**
* This class is used as a callback receiver for [PackageInstaller] events,

View file

@ -5,7 +5,7 @@ import android.content.pm.PackageInstaller
import com.aliucord.manager.installers.InstallerResult
import com.aliucord.manager.installers.UnknownInstallerError
import com.aliucord.manager.util.showToast
import dev.shiggy.manager.R
import dev.goon.manager.R
/**
* This receiver is meant to be registered dynamically in combination with [PMIntentReceiver] in order to

View file

@ -10,7 +10,7 @@ import com.aliucord.manager.installers.InstallerResult
import com.aliucord.manager.installers.pm.PMUtils
import com.aliucord.manager.util.showToast
import dev.rikka.tools.refine.Refine
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.suspendCancellableCoroutine

View file

@ -8,7 +8,7 @@ import android.os.Bundle
import android.util.Log
import com.aliucord.manager.installers.shizuku.ShizukuInstallerError
import com.aliucord.manager.installers.InstallerResult
import dev.shiggy.manager.BuildConfig
import dev.goon.manager.BuildConfig
class ShizukuIntentReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {

View file

@ -11,7 +11,7 @@ import androidx.core.content.getSystemService
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.aliucord.manager.util.IS_PROBABLY_EMULATOR
import com.aliucord.manager.util.isPlayProtectEnabled
import dev.shiggy.manager.BuildConfig
import dev.goon.manager.BuildConfig
import kotlinx.serialization.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream

View file

@ -11,28 +11,12 @@ import java.io.File
class PathManager(
private val context: Context,
) {
/**
* The Aliucord folder in which plugins/settings/themes are stored.
* Standard path: `~/Aliucord`
*/
val aliucordDir = Environment.getExternalStorageDirectory().resolve("Aliucord")
/**
* The Shiggy folder where shared Shiggy files are stored.
* Standard path: `~/Shiggy`
*/
val shiggyDir = Environment.getExternalStorageDirectory().resolve("Shiggy")
/**
* The directory in external storage in which plugins are stored by Aliucord.
*/
val pluginsDir = aliucordDir.resolve("plugins")
/**
* The settings file in which Aliucord's core uses.
*/
val coreSettingsFile = aliucordDir.resolve("settings/Aliucord.json")
/**
* Global keystore used for signing APKs.
*/

View file

@ -8,6 +8,7 @@ import com.aliucord.manager.ui.theme.Theme
@Stable
class PreferencesManager(preferences: SharedPreferences) : BasePreferenceManager(preferences) {
var theme by enumPreference("theme", Theme.System)
var amoled by booleanPreference("amoled", false)
var dynamicColor by booleanPreference("dynamic_color", true)
var devMode by booleanPreference("dev_mode", false)
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PM)

View file

@ -9,8 +9,8 @@ import androidx.core.content.getSystemService
import androidx.core.net.toUri
import com.aliucord.manager.manager.download.IDownloadManager.ProgressListener
import com.aliucord.manager.manager.download.IDownloadManager.Result
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import java.io.File

View file

@ -9,18 +9,20 @@ import androidx.core.content.getSystemService
import com.aliucord.manager.manager.download.IDownloadManager.Result
import com.aliucord.manager.patcher.util.InsufficientStorageException
import com.aliucord.manager.util.IS_PROBABLY_EMULATOR
import dev.shiggy.manager.R
import dev.goon.manager.R
import io.ktor.client.HttpClient
import io.ktor.client.request.header
import io.ktor.client.request.prepareGet
import io.ktor.client.statement.bodyAsChannel
import io.ktor.http.HttpHeaders
import io.ktor.http.contentLength
import io.ktor.http.isSuccess
import io.ktor.utils.io.readAvailable
import kotlinx.coroutines.CancellationException
import java.io.File
import java.io.IOException
import java.net.SocketTimeoutException
import java.net.URI
/**
* Handle downloading remote urls to a path with Ktor.
@ -39,55 +41,108 @@ class KtorDownloadManager(
.apply { exists() || createNewFile() }
try {
val httpStmt = http.prepareGet(url) {
header(HttpHeaders.CacheControl, "no-cache, no-store")
val downloadUrl = rewriteRawGithubUrl(url)
// Disable compression due to bug on emulators
// This header cannot be set with Android's DownloadManager
if (IS_PROBABLY_EMULATOR) {
header(HttpHeaders.AcceptEncoding, null)
// Try the CDN first (jsDelivr), then an alternate raw proxy (raw.githack.com), and finally
// fall back to the original URL if all CDN attempts fail.
val rawGithack = try {
when {
// direct raw.githubusercontent.com -> raw.githack.com
url.contains("raw.githubusercontent.com", ignoreCase = true) ->
url.replace("raw.githubusercontent.com", "raw.githack.com")
// github.com/.../raw/... -> convert to raw.githack.com/ORG/REPO/BRANCH/path
url.contains("/raw/", ignoreCase = true) && url.contains("github.com", ignoreCase = true) -> {
try {
val u = URI(url)
val segs = u.path.trimStart('/').split('/', limit = 6)
if (segs.size >= 5 && segs[2].equals("raw", ignoreCase = true)) {
"https://raw.githack.com/${segs[0]}/${segs[1]}/${segs.subList(3, segs.size).joinToString("/")}"
} else url
} catch (_: Throwable) {
url
}
}
else -> url
}
} catch (_: Throwable) {
url
}
val attempts = listOf(downloadUrl, rawGithack, url).distinct()
var lastException: Throwable? = null
var downloaded = false
for (attemptUrl in attempts) {
val httpStmt = http.prepareGet(attemptUrl) {
header(HttpHeaders.CacheControl, "no-cache, no-store")
// Disable compression due to bug on emulators
// This header cannot be set with Android's DownloadManager
if (IS_PROBABLY_EMULATOR) {
header(HttpHeaders.AcceptEncoding, null)
}
}
try {
httpStmt.execute { resp ->
if (!resp.status.isSuccess()) {
throw IOException("HTTP error ${resp.status.value} for $attemptUrl")
}
val channel = resp.bodyAsChannel()
val total = resp.contentLength() ?: 0
var retrieved = 0L
val buf = ByteArray(1024 * 1024 * 1)
var bufLen: Int
tmpOut.outputStream().use { stream ->
// Preallocate space for this file
if (total > 0 && Build.VERSION.SDK_INT >= 26) {
val storageManager = application.getSystemService<StorageManager>()!!
try {
storageManager.allocateBytes(stream.fd, total)
} catch (e: IOException) {
throw InsufficientStorageException(e.message)
}
}
while (!channel.isClosedForRead) {
bufLen = channel.readAvailable(buf)
if (bufLen <= 0) break
stream.write(buf, 0, bufLen)
stream.flush()
retrieved += bufLen
if (total > 0) {
if (retrieved > total)
throw IOException("Total bytes received exceeds header total!")
onProgressUpdate?.onUpdate(retrieved / total.toFloat())
} else {
onProgressUpdate?.onUpdate(null)
}
}
}
}
// If we reach here, the attempt succeeded
downloaded = true
break
} catch (e: CancellationException) {
// Propagate cancellations immediately
throw e
} catch (t: Throwable) {
// Record the last exception and try the next URL (if any)
lastException = t
}
}
httpStmt.execute { resp ->
val channel = resp.bodyAsChannel()
val total = resp.contentLength() ?: 0
var retrieved = 0L
val buf = ByteArray(1024 * 1024 * 1)
var bufLen: Int
tmpOut.outputStream().use { stream ->
// Preallocate space for this file
if (total > 0 && Build.VERSION.SDK_INT >= 26) {
val storageManager = application.getSystemService<StorageManager>()!!
try {
storageManager.allocateBytes(stream.fd, total)
} catch (e: IOException) {
throw InsufficientStorageException(e.message)
}
}
while (!channel.isClosedForRead) {
bufLen = channel.readAvailable(buf)
if (bufLen <= 0) break
stream.write(buf, 0, bufLen)
stream.flush()
retrieved += bufLen
if (total > 0) {
if (retrieved > total)
throw IOException("Total bytes received exceeds header total!")
onProgressUpdate?.onUpdate(retrieved / total.toFloat())
} else {
onProgressUpdate?.onUpdate(null)
}
}
}
if (!downloaded) {
// No attempt succeeded, throw the last failure to be handled by outer catch blocks
throw lastException ?: IOException("Failed to download resource from $url")
}
} catch (_: CancellationException) {
tmpOut.delete()
@ -107,6 +162,17 @@ class KtorDownloadManager(
return Result.Success(out)
}
private fun rewriteRawGithubUrl(url: String): String {
val regex = Regex("^https?://raw\\.githubusercontent\\.com/([^/]+)/([^/]+)/([^/]+)/(.*)$", RegexOption.IGNORE_CASE)
val match = regex.matchEntire(url)
return if (match != null) {
val (org, repo, branch, path) = match.destructured
"https://cdn.jsdelivr.net/gh/$org/$repo@$branch/$path"
} else {
url
}
}
/**
* Wrapper around an exception that occurred from invoking Ktor
*/

View file

@ -1,23 +0,0 @@
package com.aliucord.manager.network.models
import androidx.compose.runtime.Immutable
import com.aliucord.manager.util.serialization.ImmutableListSerializer
import kotlinx.collections.immutable.ImmutableList
import kotlinx.serialization.Serializable
@Immutable
@Serializable
data class Contributor(
val username: String,
val avatarUrl: String,
val commits: Int,
@Serializable(with = ImmutableListSerializer::class)
val repositories: ImmutableList<Repository>,
) {
@Immutable
@Serializable
data class Repository(
val name: String,
val commits: Int,
)
}

View file

@ -0,0 +1,18 @@
package com.aliucord.manager.network.models
import kotlinx.serialization.Serializable
@Serializable
data class Developer(
val username: String,
val avatarUrl: String,
val commits: Int,
val repositories: List<Repository>,
val role: String? = null
) {
@Serializable
data class Repository(
val name: String,
val commits: Int
)
}

View file

@ -2,7 +2,7 @@ package com.aliucord.manager.network.services
import android.util.Log
import com.aliucord.manager.network.utils.*
import dev.shiggy.manager.BuildConfig
import dev.goon.manager.BuildConfig
import io.ktor.client.HttpClient
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.request

View file

@ -26,8 +26,8 @@ class ShiggyGithubService(
}
companion object {
const val ORG = "kmmiio99o"
const val MANAGER_REPO = "ShiggyManager"
const val XPOSED_REPO = "ShiggyXposed"
const val ORG = "OTKUSteyler"
const val MANAGER_REPO = "GoonManager"
const val XPOSED_REPO = "GoonXposed"
}
}

View file

@ -59,7 +59,7 @@ data class SemVer(
?: throw IllegalArgumentException("Invalid semver string $version")
fun parseOrNull(version: String): SemVer? {
val parts = version.removePrefix("v").split(".")
val parts = version.removePrefix("v").removePrefix("V").split(".")
if (parts.size != 3)
return null

View file

@ -6,6 +6,9 @@ import kotlinx.serialization.Serializable
/**
* Data stored inside patched APKs as ~~"aliucord.json"~~ "shiggy.json" in order to preserve install-time information about Aliucord and the Manager.
* Metadata about an Aliucord installation embedded in the APK.
* @param options The patch options used for this installation
* @param goonXposedVersion The version of GoonXposed used for this installation
*/
@Serializable
data class InstallMetadata(
@ -47,5 +50,5 @@ data class InstallMetadata(
/**
* Version of ShiggyXposed embedded into the APK.
*/
val shiggyXposedVersion: SemVer?,
val goonXposedVersion: SemVer,
)

View file

@ -9,8 +9,8 @@ import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.DownloadStep
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.ui.util.InstallNotifications
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.delay
import org.koin.core.component.KoinComponent

View file

@ -3,7 +3,7 @@ package com.aliucord.manager.patcher.steps
import android.os.Parcelable
import androidx.annotation.StringRes
import androidx.compose.runtime.Immutable
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.parcelize.Parcelize
/**

View file

@ -10,7 +10,7 @@ import com.aliucord.manager.manager.download.KtorDownloadManager
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.util.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent

View file

@ -9,7 +9,7 @@ import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.util.InsufficientStorageException
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File

View file

@ -10,7 +10,7 @@ import com.aliucord.manager.patcher.steps.base.DownloadStep
import com.aliucord.manager.patcher.steps.base.IDexProvider
import com.aliucord.manager.patcher.steps.patch.ReorganizeDexStep
import com.github.diamondminer88.zip.ZipReader
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -3,7 +3,7 @@ package com.aliucord.manager.patcher.steps.download
import com.aliucord.manager.manager.PathManager
import com.aliucord.manager.network.services.RNATrackerService.Companion.BASE_URL
import com.aliucord.manager.patcher.steps.base.DownloadDiscordRNAStep
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.inject
class DownloadDiscordRNABaseStep : DownloadDiscordRNAStep() {

View file

@ -3,7 +3,7 @@ package com.aliucord.manager.patcher.steps.download
import com.aliucord.manager.manager.PathManager
import com.aliucord.manager.network.services.RNATrackerService.Companion.BASE_URL
import com.aliucord.manager.patcher.steps.base.DownloadDiscordRNAStep
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.inject
class DownloadDiscordRNALangStep : DownloadDiscordRNAStep() {

View file

@ -4,7 +4,7 @@ import android.os.Build
import com.aliucord.manager.manager.PathManager
import com.aliucord.manager.network.services.RNATrackerService.Companion.BASE_URL
import com.aliucord.manager.patcher.steps.base.DownloadDiscordRNAStep
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.inject
class DownloadDiscordRNALibStep : DownloadDiscordRNAStep() {

View file

@ -3,7 +3,7 @@ package com.aliucord.manager.patcher.steps.download
import com.aliucord.manager.manager.PathManager
import com.aliucord.manager.network.services.RNATrackerService.Companion.BASE_URL
import com.aliucord.manager.patcher.steps.base.DownloadDiscordRNAStep
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.inject
class DownloadDiscordRNAResourcesStep : DownloadDiscordRNAStep() {

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.patcher.steps.download
import androidx.compose.runtime.Stable
import com.aliucord.manager.manager.PathManager
import com.aliucord.manager.patcher.steps.base.DownloadStep
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -11,8 +11,8 @@ import com.aliucord.manager.patcher.steps.base.*
import com.aliucord.manager.patcher.steps.patch.ReorganizeDexStep
import com.aliucord.manager.patcher.steps.prepare.FetchInfoStep
import com.aliucord.manager.ui.components.dialogs.CustomComponentVersionPicker
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -5,7 +5,7 @@ import com.aliucord.manager.manager.PathManager
import com.aliucord.manager.patcher.steps.base.DownloadStep
import com.aliucord.manager.patcher.steps.base.IDexProvider
import com.aliucord.manager.patcher.steps.patch.ReorganizeDexStep
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -11,8 +11,8 @@ import com.aliucord.manager.patcher.steps.base.DownloadStep
import com.aliucord.manager.patcher.steps.base.StepState
import com.aliucord.manager.patcher.steps.prepare.FetchInfoStep
import com.aliucord.manager.ui.components.dialogs.CustomComponentVersionPicker
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -6,7 +6,7 @@ import com.aliucord.manager.network.utils.SemVer
import com.aliucord.manager.network.utils.getOrThrow
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.base.DownloadStep
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.inject
class DownloadShiggyXposedStep : DownloadStep() {
@ -22,7 +22,7 @@ class DownloadShiggyXposedStep : DownloadStep() {
override suspend fun execute(container: StepRunner) {
val latestRelease = shiggyGithubService.getLatestXposedRelease().getOrThrow()
container.log("Latest ShiggyXposed release is ${latestRelease.name}")
container.log("Latest GoonXposed release is ${latestRelease.name}")
targetVersion = SemVer.parse(latestRelease.name)
targetUrl = latestRelease.assets.first { it.name == "app-release.apk" }.browserDownloadUrl

View file

@ -7,7 +7,7 @@ import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.download.CopyDependenciesStep
import com.github.diamondminer88.zip.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -5,7 +5,7 @@ import com.aliucord.manager.manager.PreferencesManager
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -6,17 +6,18 @@ import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.download.CopyDependenciesStep
import com.aliucord.manager.patcher.steps.download.DownloadShiggyXposedStep
import com.aliucord.manager.patcher.util.Signer
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.lsposed.lspatch.share.LSPConfig
import org.lsposed.patch.LSPatch
import org.lsposed.patch.util.Logger
import java.io.File
import java.util.*
class InjectShiggyXposedStep : Step() {
class InjectGoonXposedStep : Step() {
override val group: StepGroup = StepGroup.Install
override val localizedName: Int = R.string.patch_step_inject_shiggy
override val localizedName: Int = R.string.patch_step_inject_goon
suspend fun patch(
container: StepRunner,
@ -82,7 +83,15 @@ class InjectShiggyXposedStep : Step() {
// FilenameUtils.getBaseName(apkFileName),
// LSPConfig.instance.VERSION_CODE)
// )
val patchedApkName = "${baseName}-${LSPConfig.instance.VERSION_CODE}-lspatched.apk"
// Note: LSPatch uses Locale.getDefault() which can produce locale-specific numerals
// (e.g., Arabic numerals on Arabic locales). We must use Locale.US to ensure
// consistent filename matching regardless of device locale.
val patchedApkName = String.format(
Locale.US,
"%s-%d-lspatched.apk",
baseName,
LSPConfig.instance.VERSION_CODE
)
val patchedApk = File(tempDir, patchedApkName)
if (patchedApk.exists()) {

View file

@ -14,7 +14,7 @@ import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.aliucord.manager.ui.util.InstallNotifications
import com.aliucord.manager.util.isPackageInstalled
import com.aliucord.manager.util.isPlayProtectEnabled
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -5,7 +5,7 @@ import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.download.CopyDependenciesStep
import com.aliucord.manager.patcher.util.Signer
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
/**

View file

@ -8,7 +8,7 @@ import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.download.CopyDependenciesStep
import com.aliucord.manager.patcher.steps.download.DownloadAliuhookStep
import com.github.diamondminer88.zip.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
/**

View file

@ -30,7 +30,7 @@ import com.aliucord.manager.ui.screens.patchopts.PatchOptions.IconReplacement
import com.aliucord.manager.util.getResBytes
import com.github.diamondminer88.zip.ZipWriter
import com.google.devrel.gmscore.tools.apk.arsc.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.ByteArrayOutputStream

View file

@ -8,7 +8,7 @@ import com.aliucord.manager.patcher.util.ManifestPatcher
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.github.diamondminer88.zip.ZipReader
import com.github.diamondminer88.zip.ZipWriter
import dev.shiggy.manager.R
import dev.goon.manager.R
/**
* Patch the APK's AndroidManifest.xml

View file

@ -7,7 +7,7 @@ import com.aliucord.manager.patcher.steps.base.IDexProvider
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.download.CopyDependenciesStep
import com.github.diamondminer88.zip.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -8,8 +8,8 @@ import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.download.*
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.github.diamondminer88.zip.ZipWriter
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
import kotlinx.serialization.json.Json
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@ -31,7 +31,7 @@ class SaveMetadataStep(private val options: PatchOptions) : Step(), KoinComponen
val aliuhook = container.getStepOrNull<DownloadAliuhookStep>()
val injector = container.getStepOrNull<DownloadInjectorStep>()
val patches = container.getStepOrNull<DownloadPatchesStep>()
val shiggyXposed = container.getStepOrNull<DownloadShiggyXposedStep>()
val goonXposed = container.getStepOrNull<DownloadShiggyXposedStep>()
val metadata = InstallMetadata(
options = options,
@ -41,12 +41,12 @@ class SaveMetadataStep(private val options: PatchOptions) : Step(), KoinComponen
injectorVersion = injector?.targetVersion,
patchesVersion = patches?.targetVersion,
lspatchVersion = LSPConfig.instance.VERSION_CODE,
shiggyXposedVersion = shiggyXposed?.targetVersion,
goonXposedVersion = goonXposed?.targetVersion ?: SemVer.parse("0.0.0"), // Provide a default if null
)
container.log("Writing serialized install metadata to APK")
ZipWriter(apk, /* append = */ true).use {
it.writeEntry("shiggy.json", json.encodeToString<InstallMetadata>(metadata))
it.writeEntry("goon.json", json.encodeToString<InstallMetadata>(metadata))
}
}
}

View file

@ -17,7 +17,7 @@ import com.github.diamondminer88.zip.ZipReader
import com.github.difflib.DiffUtils
import com.github.difflib.UnifiedDiffUtils
import com.github.difflib.patch.Patch
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.FileNotFoundException

View file

@ -10,7 +10,7 @@ import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.base.StepState
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.aliucord.manager.util.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -7,7 +7,7 @@ import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.aliucord.manager.ui.screens.patchopts.VersionPreference
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import kotlin.properties.Delegates

View file

@ -7,7 +7,7 @@ import com.aliucord.manager.network.utils.getOrThrow
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -6,7 +6,7 @@ import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.base.StepState
import dev.shiggy.manager.R
import dev.goon.manager.R
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

View file

@ -252,6 +252,8 @@ object ManifestPatcher {
extractNativeLibs ?: false
private var shouldAddMetadata =
addManagerMetadata ?: false
private var shouldAddCleartext = true
override fun attr(
ns: String?,
@ -269,6 +271,12 @@ object ManifestPatcher {
shouldAddExtractNativeLibs = false
if (name == DEBUGGABLE)
shouldAddDebuggable = false
if (name == "usesCleartextTraffic") {
shouldAddCleartext = false
super.attr(ns, name, 0x010104ec, TYPE_INT_BOOLEAN, 1)
return
}
super.attr(
ns,
name,
@ -425,7 +433,15 @@ object ManifestPatcher {
0
)
}
if (shouldAddCleartext) {
super.attr(
ANDROID_NAMESPACE,
"usesCleartextTraffic",
0x010104ec,
TYPE_INT_BOOLEAN,
1
)
}
super.end()
}
}

View file

@ -7,7 +7,7 @@ package com.aliucord.manager.patcher.util
import com.aliucord.manager.manager.PathManager
import com.android.apksig.ApkSigner
import dev.shiggy.manager.BuildConfig
import dev.goon.manager.BuildConfig
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import org.bouncycastle.cert.X509v3CertificateBuilder

View file

@ -8,7 +8,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import cafe.adriel.voyager.navigator.LocalNavigator
import com.aliucord.manager.util.back
import dev.shiggy.manager.R
import dev.goon.manager.R
/**
* Standalone back button for interacting with the current navigator.

View file

@ -19,7 +19,7 @@ import androidx.core.graphics.applyCanvas
import androidx.core.graphics.createBitmap
import androidx.core.graphics.drawable.toDrawable
import com.aliucord.manager.ui.screens.patchopts.PatchOptions.IconReplacement
import dev.shiggy.manager.R
import dev.goon.manager.R
// Sizing information is obtained from here:
// https://medium.com/google-design/designing-adaptive-icons-515af294c783

View file

@ -17,13 +17,13 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import coil3.compose.SubcomposeAsyncImage
import com.aliucord.manager.network.models.Contributor
import com.aliucord.manager.network.models.Developer
import com.valentinilk.shimmer.shimmer
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun ContributorCommitsItem(
user: Contributor,
user: Developer,
modifier: Modifier = Modifier,
) {
val uriHandler = LocalUriHandler.current

View file

@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun LoadFailure(modifier: Modifier = Modifier) {

View file

@ -12,7 +12,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun ProjectHeader(

View file

@ -9,7 +9,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.aliucord.manager.ui.util.mirrorVertically
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun ResetToDefaultButton(

View file

@ -16,7 +16,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.aliucord.manager.network.utils.SemVer
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun CustomComponentVersionPicker(

View file

@ -8,7 +8,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun InstallerAbortDialog(

View file

@ -13,7 +13,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun NetworkWarningDialog(

View file

@ -17,7 +17,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.aliucord.manager.ui.theme.customColors
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun PlayProtectDialog(

View file

@ -19,8 +19,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import androidx.core.net.toUri
import com.google.accompanist.permissions.*
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
@Composable
@OptIn(ExperimentalPermissionsApi::class)

View file

@ -16,8 +16,8 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import androidx.core.net.toUri
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
@Composable
fun UnknownSourcesPermissionDialog() {

View file

@ -11,7 +11,7 @@ import androidx.compose.ui.tooling.preview.*
import com.aliucord.manager.ui.screens.patching.components.TextBanner
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.theme.customColors
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -1,20 +0,0 @@
package com.aliucord.manager.ui.previews.dialogs
import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.screens.plugins.components.dialogs.UninstallPluginDialog
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
private fun UninstallPluginDialogPreview() {
ManagerTheme {
UninstallPluginDialog(
pluginName = "FakeNitro",
onConfirm = {},
onDismiss = {},
)
}
}

View file

@ -14,7 +14,7 @@ import com.aliucord.manager.ui.screens.iconopts.IconOptionsMode
import com.aliucord.manager.ui.screens.iconopts.IconOptionsScreenContent
import com.aliucord.manager.ui.screens.patchopts.PatchOptions.IconReplacement
import com.aliucord.manager.ui.theme.ManagerTheme
import dev.shiggy.manager.R
import dev.goon.manager.R
import dev.zt64.compose.pipette.HsvColor
import java.io.ByteArrayOutputStream

View file

@ -1,52 +0,0 @@
package com.aliucord.manager.ui.previews.screens.about
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.*
import com.aliucord.manager.network.models.Contributor
import com.aliucord.manager.ui.screens.about.AboutScreenContent
import com.aliucord.manager.ui.screens.about.AboutScreenState
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.util.emptyImmutableList
import com.aliucord.manager.util.serialization.ImmutableListSerializer
import kotlinx.collections.immutable.*
import kotlinx.serialization.json.Json
// This preview has scrollable content that cannot be properly viewed from an IDE preview
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
private fun AboutScreenLoadedPreview(
@PreviewParameter(ContributorsProvider::class) contributors: ImmutableList<Contributor>,
) {
ManagerTheme {
AboutScreenContent(
state = remember { mutableStateOf(AboutScreenState.Loaded(contributors)) },
)
}
}
private class ContributorsProvider : PreviewParameterProvider<ImmutableList<Contributor>> {
private val realDataRaw =
"[{\"username\":\"maisymoe\",\"avatarUrl\":\"https://avatars.githubusercontent.com/u/61095277?v=4\",\"repositories\":]"
private val realData =
Json.decodeFromString(ImmutableListSerializer(Contributor.serializer()), realDataRaw)
override val values =
sequenceOf(
emptyImmutableList<Contributor>(),
persistentListOf(
Contributor(
username =
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
avatarUrl = "UNUSED",
commits = Int.MAX_VALUE,
repositories =
(realData[0].repositories + realData[0].repositories)
.toImmutableList(),
)
),
realData,
)
}

View file

@ -34,7 +34,6 @@ private fun HomeScreenLoadedPreview(
onUpdate = {},
onOpenApp = {},
onOpenAppInfo = {},
onOpenPlugins = {},
onUninstall = {},
)
}

View file

@ -1,29 +0,0 @@
package com.aliucord.manager.ui.previews.screens.plugins
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.screens.plugins.PluginsScreenContent
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.util.emptyImmutableList
// This preview has interactable content that cannot be tested from an IDE preview
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
private fun PluginsScreenFailedPreview() {
val filterState = remember { mutableStateOf("") }
ManagerTheme {
PluginsScreenContent(
searchText = filterState,
setSearchText = filterState::value::set,
isError = true,
plugins = emptyImmutableList(),
onPluginUninstall = {},
onPluginChangelog = {},
onPluginToggle = { name, enabled -> },
)
}
}

View file

@ -1,92 +0,0 @@
package com.aliucord.manager.ui.previews.screens.plugins
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.screens.plugins.PluginsScreenContent
import com.aliucord.manager.ui.screens.plugins.model.PluginItem
import com.aliucord.manager.ui.screens.plugins.model.PluginManifest
import com.aliucord.manager.ui.theme.ManagerTheme
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import java.util.UUID
// This preview has scrollable/interactable content that cannot be tested from an IDE preview
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
private fun PluginsScreenLoadedPreview() {
val filterState = remember { mutableStateOf("test") }
ManagerTheme {
PluginsScreenContent(
searchText = filterState,
setSearchText = filterState::value::set,
isError = false,
plugins = plugins,
onPluginUninstall = {},
onPluginChangelog = {},
onPluginToggle = { name, enabled -> },
)
}
}
private val plugins: ImmutableList<PluginItem> = persistentListOf(
PluginItem(
path = UUID.randomUUID().toString(),
manifest = PluginManifest(
name = "CloseDMs",
authors = persistentListOf(
PluginManifest.Author(name = "Diamond", id = 0L),
),
description = "Shortcut to close DMs in the DM context menu.",
version = "1.0.0",
updateUrl = "",
changelog = "",
changelogMedia = null,
)
),
PluginItem(
path = UUID.randomUUID().toString(),
manifest = PluginManifest(
name = "ConfigurableStickerSizes",
authors = persistentListOf(
PluginManifest.Author(name = "rushii", id = 0L, hyperlink = false),
),
description = "Makes sticker sizes configurable.",
version = "1.1.5",
updateUrl = "",
changelog = "",
changelogMedia = null,
)
),
PluginItem(
path = UUID.randomUUID().toString(),
manifest = PluginManifest(
name = "AudioPlayer",
authors = persistentListOf(
PluginManifest.Author(name = "rushii", id = 0L, hyperlink = false),
),
description = "Makes audio files playable.",
version = "0.0.1",
updateUrl = "",
changelog = "",
changelogMedia = null,
)
),
PluginItem(
path = UUID.randomUUID().toString(),
manifest = PluginManifest(
name = "TypingIndicators",
authors = persistentListOf(
PluginManifest.Author(name = "rushii", id = 0L, hyperlink = false),
),
description = "Adds typing indicators to channels that people are currently typing in.",
version = "1.1.0",
updateUrl = "",
changelog = "",
changelogMedia = null,
)
),
)

View file

@ -1,29 +0,0 @@
package com.aliucord.manager.ui.previews.screens.plugins
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.screens.plugins.PluginsScreenContent
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.util.emptyImmutableList
// This preview has interactable content that cannot be tested from an IDE preview
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
private fun PluginsScreenNonePreview() {
val filterState = remember { mutableStateOf("") }
ManagerTheme {
PluginsScreenContent(
searchText = filterState,
setSearchText = filterState::value::set,
isError = false,
plugins = emptyImmutableList(),
onPluginUninstall = {},
onPluginChangelog = {},
onPluginToggle = { name, enabled -> },
)
}
}

View file

@ -2,56 +2,67 @@ package com.aliucord.manager.ui.screens.about
import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import com.aliucord.manager.network.models.Contributor
import com.aliucord.manager.network.models.Developer
import com.aliucord.manager.network.services.HttpService
import com.aliucord.manager.network.utils.fold
import com.aliucord.manager.ui.util.toUnsafeImmutable
import com.aliucord.manager.util.launchIO
import io.ktor.client.request.url
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerialName
import kotlinx.collections.immutable.persistentListOf
class AboutModel(
private val http: HttpService,
) : StateScreenModel<AboutScreenState>(AboutScreenState.Loading) {
init {
fetchContributors()
fetchDevelopers()
}
fun fetchContributors() = screenModelScope.launchIO {
fun fetchDevelopers() = screenModelScope.launchIO {
mutableState.value = AboutScreenState.Loading
// Use a curated static list of GitHub usernames (profiles + static avatar URLs).
// This avoids pulling from a specific repo and lets us include people
// who are not contributors to any particular repository.
val staticContributors = persistentListOf(
Contributor(
username = "rushiiMachine",
avatarUrl = "https://github.com/rushiiMachine.png",
val allDevelopers = persistentListOf(
Developer(
username = "OTKUSteyler",
avatarUrl = "https://github.com/OTKUSteyler.png",
commits = 0,
repositories = persistentListOf<com.aliucord.manager.network.models.Contributor.Repository>()
repositories = emptyList(),
role = "GoonCord - Creator"
),
Contributor(
username = "maisymoe",
avatarUrl = "https://github.com/maisymoe.png",
commits = 0,
repositories = persistentListOf<com.aliucord.manager.network.models.Contributor.Repository>()
),
Contributor(
Developer(
username = "kmmiio99o",
avatarUrl = "https://github.com/kmmiio99o.png",
commits = 0,
repositories = persistentListOf<com.aliucord.manager.network.models.Contributor.Repository>()
repositories = emptyList(),
role = "ShiggyCord - Creator"
),
Contributor(
Developer(
username = "rushiiMachine",
avatarUrl = "https://github.com/rushiiMachine.png",
commits = 0,
repositories = emptyList(),
role = "Manager - Creator"
),
Developer(
username = "maisymoe",
avatarUrl = "https://github.com/maisymoe.png",
commits = 0,
repositories = emptyList(),
role = "Vendetta - Creator"
),
Developer(
username = "pylixonly",
avatarUrl = "https://github.com/pylixonly.png",
commits = 0,
repositories = persistentListOf<com.aliucord.manager.network.models.Contributor.Repository>()
)
repositories = emptyList(),
role = "Bunny - Creator"
),
Developer(
username = "jonatanktk",
avatarUrl = "https://github.com/jonatanktk.png",
commits = 0,
repositories = emptyList(),
role = "Random Person there"
),
)
mutableState.value = AboutScreenState.Loaded(staticContributors.toUnsafeImmutable())
mutableState.value = AboutScreenState.Loaded(allDevelopers.toUnsafeImmutable())
}
}

View file

@ -10,6 +10,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@ -20,15 +21,16 @@ import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.koin.koinScreenModel
import com.aliucord.manager.ui.components.*
import com.aliucord.manager.ui.screens.about.components.LeadContributor
import com.aliucord.manager.ui.screens.about.components.RegularContributorListItem
import com.aliucord.manager.ui.util.paddings.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
@Parcelize
class AboutScreen : Screen, Parcelable {
@IgnoredOnParcel override val key = "About"
@IgnoredOnParcel
override val key = "About"
@Composable
override fun Content() {
@ -41,107 +43,92 @@ class AboutScreen : Screen, Parcelable {
@Composable
fun AboutScreenContent(state: State<AboutScreenState>) {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.navigation_about_manager)) },
navigationIcon = { BackButton() },
)
}
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.navigation_about_manager)) },
navigationIcon = { BackButton() },
)
}
) { paddingValues ->
LazyColumn(
verticalArrangement = Arrangement.spacedBy(2.dp),
horizontalAlignment = Alignment.CenterHorizontally,
contentPadding =
paddingValues
.exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top)
.add(PaddingValues(vertical = 16.dp)),
modifier =
Modifier.padding(paddingValues.exclude(PaddingValuesSides.Bottom))
.padding(horizontal = 14.dp),
verticalArrangement = Arrangement.spacedBy(2.dp),
horizontalAlignment = Alignment.CenterHorizontally,
contentPadding = paddingValues
.exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top)
.add(PaddingValues(vertical = 16.dp)),
modifier = Modifier
.padding(paddingValues.exclude(PaddingValuesSides.Bottom))
) {
item(key = "MANAGER_CREDIT_DISCLAIMER_BANNER") {
Box(
contentAlignment = Alignment.Center,
modifier =
Modifier.padding(bottom = 24.dp)
.border(
width = 2.dp,
color = MaterialTheme.colorScheme.surfaceVariant,
shape = MaterialTheme.shapes.medium
)
.clip(MaterialTheme.shapes.medium)
.background(MaterialTheme.colorScheme.surfaceContainerHigh)
) {
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(horizontal = 20.dp, vertical = 14.dp)
) {
Text(
text =
stringResource(
R.string.about_manager_credit_disclaimer_notice
),
style = MaterialTheme.typography.labelMedium,
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 8.dp)
.fillMaxWidth()
.border(
width = 1.dp,
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.3f),
shape = MaterialTheme.shapes.large
)
.clip(MaterialTheme.shapes.large)
.background(MaterialTheme.colorScheme.surfaceContainerLow)
) {
Text(
text = stringResource(R.string.about_manager_credit_disclaimer_notice),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(horizontal = 20.dp, vertical = 16.dp)
)
}
}
item(key = "PROJECT_HEADER") {
Box(modifier = Modifier.padding(horizontal = 16.dp)) {
ProjectHeader()
}
}
item(key = "TEAM_SPACER") {
Spacer(modifier = Modifier.height(32.dp))
}
when (val currentState = state.value) {
AboutScreenState.Loading -> {
item(key = "LOADING") {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 48.dp)
) {
CircularProgressIndicator()
}
}
}
}
item(key = "PROJECT_HEADER") { ProjectHeader() }
item(key = "HEADER_DIVIDER") {
TextDivider(
text = stringResource(R.string.contributors_lead),
modifier = Modifier.padding(top = 18.dp, bottom = 20.dp),
)
}
item(key = "MAIN_CONTRIBUTORS") {
Row(
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth(),
) {
LeadContributor("C0C0B01", stringResource(R.string.lead_role_kettu))
LeadContributor("kmmiio99o", stringResource(R.string.lead_role_shiggycord))
LeadContributor("pylixonly", stringResource(R.string.lead_role_bunny))
}
}
item(key = "CONTRIBUTORS_DIVIDER") {
TextDivider(
text = stringResource(R.string.contributors),
modifier = Modifier.padding(top = 16.dp, bottom = 6.dp)
)
}
when (val state = state.value) {
AboutScreenState.Loading ->
item(key = "CONTRIBUTIONS_LOADING") {
Box(
contentAlignment = Alignment.Center,
content = { CircularProgressIndicator() },
modifier = Modifier.fillMaxWidth().padding(vertical = 38.dp),
)
}
AboutScreenState.Failure ->
item(key = "LOAD_FAILURE") {
LoadFailure(modifier = Modifier.fillMaxSize().padding(vertical = 38.dp))
}
is AboutScreenState.Loaded -> {
// Render the two requested contributors as LeadContributor entries
item(key = "SELECTED_CONTRIBUTORS") {
Row(
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth(),
AboutScreenState.Failure -> {
item(key = "LOAD_FAILURE") {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 48.dp)
) {
LeadContributor("maisymoe", "Creator - Vendetta")
LeadContributor("rushiiMachine", "Manager - Creator")
LoadFailure()
}
}
}
is AboutScreenState.Loaded -> {
itemsIndexed(
items = currentState.contributors,
key = { index, developer -> developer.username }
) { index, developer ->
RegularContributorListItem(
contributor = developer,
isLast = index == currentState.contributors.lastIndex
)
}
}
}
}
}

View file

@ -1,10 +1,10 @@
package com.aliucord.manager.ui.screens.about
import com.aliucord.manager.network.models.Contributor
import com.aliucord.manager.network.models.Developer
import kotlinx.collections.immutable.ImmutableList
sealed interface AboutScreenState {
data object Loading : AboutScreenState
data object Failure : AboutScreenState
data class Loaded(val contributors: ImmutableList<Contributor>) : AboutScreenState
data class Loaded(val contributors: ImmutableList<Developer>) : AboutScreenState
}

View file

@ -0,0 +1,96 @@
package com.aliucord.manager.ui.screens.about.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import coil3.compose.SubcomposeAsyncImage
import com.aliucord.manager.network.models.Developer
import com.valentinilk.shimmer.shimmer
@Composable
fun RegularContributorListItem(
contributor: Developer,
isLast: Boolean = false,
modifier: Modifier = Modifier
) {
val uriHandler = LocalUriHandler.current
Column(modifier = modifier.fillMaxWidth()) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable(
onClick = { uriHandler.openUri("https://github.com/${contributor.username}") }
)
.padding(horizontal = 24.dp, vertical = 16.dp)
) {
SubcomposeAsyncImage(
model = contributor.avatarUrl,
contentDescription = contributor.username,
contentScale = ContentScale.Crop,
loading = {
Surface(
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
.shimmer()
) {}
},
error = {
Surface(
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
) {}
},
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
)
Spacer(modifier = Modifier.width(20.dp))
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = contributor.username,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.height(4.dp))
contributor.role?.let { role ->
Text(
text = role,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
if (!isLast) {
HorizontalDivider(
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.1f),
thickness = 1.dp,
modifier = Modifier.padding(start = 100.dp, end = 24.dp)
)
}
}
}

View file

@ -1,94 +1,96 @@
package com.aliucord.manager.ui.screens.about.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil3.compose.SubcomposeAsyncImage
import com.aliucord.manager.network.models.Developer
import com.valentinilk.shimmer.shimmer
@Composable
fun LeadContributor(
name: String,
roles: String,
username: String = name,
modifier: Modifier = Modifier,
fun LeadContributorItem(
contributor: Developer,
isLast: Boolean = false,
modifier: Modifier = Modifier
) {
val uriHandler = LocalUriHandler.current
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier =
modifier.clickable(
onClick = {
uriHandler.openUri("https://github.com/$username")
},
indication = ripple(bounded = false, radius = 90.dp),
interactionSource = remember(::MutableInteractionSource)
)
.widthIn(min = 100.dp)
) {
SubcomposeAsyncImage(
model = "https://github.com/$username.png",
contentDescription = username,
Column(modifier = modifier.fillMaxWidth()) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable(
onClick = { uriHandler.openUri("https://github.com/${contributor.username}") }
)
.padding(horizontal = 24.dp, vertical = 16.dp)
) {
SubcomposeAsyncImage(
model = contributor.avatarUrl,
contentDescription = contributor.username,
contentScale = ContentScale.Crop,
loading = {
Surface(
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
.shimmer()
) {}
},
error = {
Surface(
content = {},
tonalElevation = 2.dp,
modifier = Modifier.fillMaxSize().shimmer(),
)
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
) {}
},
modifier = Modifier.size(80.dp).clip(CircleShape),
)
modifier = Modifier
.size(56.dp)
.clip(CircleShape)
)
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = name, style = MaterialTheme.typography.titleMedium.copy(fontSize = 18.sp))
Spacer(modifier = Modifier.width(20.dp))
val roleParts = roles.split(Regex("\\s*-\\s*"), limit = 2)
if (roleParts.size == 2) {
// Render left and right parts on two separate lines, removing the dash
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = roleParts[0],
style =
MaterialTheme.typography.titleSmall.copy(
color =
MaterialTheme.colorScheme.onSurface.copy(
alpha = 0.6f
)
)
)
Text(
text = roleParts[1],
style =
MaterialTheme.typography.bodySmall.copy(
color =
MaterialTheme.colorScheme.onSurface.copy(
alpha = 0.6f
)
)
)
} else {
Text(
text = roles,
style =
MaterialTheme.typography.titleSmall.copy(
color =
MaterialTheme.colorScheme.onSurface.copy(
alpha = 0.6f
)
)
text = contributor.username,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onSurface,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.height(4.dp))
contributor.role?.let { role ->
Text(
text = role,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
if (!isLast) {
HorizontalDivider(
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.1f),
thickness = 1.dp,
modifier = Modifier.padding(start = 100.dp, end = 24.dp)
)
}
}
}

View file

@ -24,8 +24,8 @@ import com.aliucord.manager.ui.util.DiscordVersion
import com.aliucord.manager.ui.util.toUnsafeImmutable
import com.aliucord.manager.util.*
import com.github.diamondminer88.zip.ZipReader
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@ -51,7 +51,7 @@ class HomeModel(
private val refreshingLock = Mutex()
private var remoteDataJson: BuildInfo? = null
private var trackerIndexJson: RNATrackerIndex? = null
private var latestShiggyXposedVersion: SemVer? = null
private var latestGoonXposedVersion: SemVer? = null
private var latestAliuhookVersion: SemVer? = null
init {
@ -122,7 +122,7 @@ class HomeModel(
val metadata = try {
val applicationInfo = application.packageManager.getApplicationInfo(packageName, 0)
val metadataFile = ZipReader(applicationInfo.publicSourceDir)
.use { it.openEntry("shiggy.json")?.read() }
.use { it.openEntry("goon.json")?.read() }
@OptIn(ExperimentalSerializationApi::class)
metadataFile?.let { json.decodeFromStream<InstallMetadata>(it.inputStream()) }
@ -146,27 +146,60 @@ class HomeModel(
try {
val packageManager = application.packageManager
val aliucordInstallations = packages.mapNotNull { pkg ->
// `longVersionCode` is unnecessary since Discord doesn't use `versionCodeMajor`
@Suppress("DEPRECATION")
val versionCode = pkg.versionCode
val versionName = pkg.versionName ?: return@mapNotNull null
val applicationInfo = pkg.applicationInfo ?: return@mapNotNull null
try {
@Suppress("DEPRECATION")
val versionCode = pkg.versionCode
val versionName = pkg.versionName ?: return@mapNotNull null
val applicationInfo = pkg.applicationInfo ?: return@mapNotNull null
InstallData(
name = packageManager.getApplicationLabel(applicationInfo).toString(),
packageName = pkg.packageName,
isUpToDate = isInstallationUpToDate(pkg),
icon = packageManager
.getApplicationIcon(applicationInfo)
.toBitmap()
.asImageBitmap()
.let(::BitmapPainter),
version = DiscordVersion.Existing(
type = DiscordVersion.parseVersionType(versionCode),
name = versionName.split("-")[0].trim(),
code = versionCode,
),
)
val name = try {
packageManager.getApplicationLabel(applicationInfo).toString()
} catch (e: Exception) {
Log.w(BuildConfig.TAG, "Failed to get label for ${pkg.packageName}", e)
null
} ?: return@mapNotNull null
val icon = try {
packageManager.getApplicationIcon(applicationInfo)
.toBitmap()
.asImageBitmap()
.let(::BitmapPainter)
} catch (e: Exception) {
Log.w(BuildConfig.TAG, "Failed to get icon for ${pkg.packageName}", e)
null
} ?: return@mapNotNull null
// Defensive: check for any other possible nulls or bad data
if (pkg.packageName.isNullOrEmpty()) {
Log.w(BuildConfig.TAG, "Package name is null or empty for a package")
return@mapNotNull null
}
InstallData(
name = name,
packageName = pkg.packageName,
isUpToDate = try {
isInstallationUpToDate(pkg)
} catch (e: Exception) {
Log.w(BuildConfig.TAG, "Failed to check up-to-date for ${pkg.packageName}", e)
false
},
icon = icon,
version = try {
DiscordVersion.Existing(
type = DiscordVersion.parseVersionType(versionCode),
name = versionName.split("-")[0].trim(),
code = versionCode,
)
} catch (e: Exception) {
Log.w(BuildConfig.TAG, "Failed to parse version for ${pkg.packageName}", e)
null
} ?: return@mapNotNull null,
)
} catch (e: Exception) {
Log.w(BuildConfig.TAG, "Failed to process package ${pkg.packageName}", e)
null
}
}
mainThread {
@ -203,7 +236,7 @@ class HomeModel(
private suspend fun fetchRemoteData() {
listOf(
// // These aren't needed by Shiggy
// // These aren't needed by Goon
// screenModelScope.launch(Dispatchers.IO) {
// github.getBuildData().fold(
// success = { remoteDataJson = it },
@ -224,14 +257,18 @@ class HomeModel(
},
screenModelScope.launch(Dispatchers.IO) {
wtGithub.getLatestXposedRelease().fold(
success = { latestShiggyXposedVersion = SemVer.parse(it.name) },
fail = { Log.w(BuildConfig.TAG, "Failed to fetch latest ShiggyXposed version", it) },
success = {
val versionName = it.name
val truncatedVersion = versionName.split(".").take(3).joinToString(".")
latestGoonXposedVersion = SemVer.parse(truncatedVersion)
},
fail = { Log.w(BuildConfig.TAG, "Failed to fetch latest GoonXposed version", it) },
)
},
).joinAll()
if (trackerIndexJson == null /* remoteDataJson == null || latestAliuhookVersion == null */ || latestShiggyXposedVersion == null) {
if (trackerIndexJson == null /* remoteDataJson == null || latestAliuhookVersion == null */ || latestGoonXposedVersion == null) {
mainThread { application.showToast(R.string.home_network_fail) }
}
}
@ -270,7 +307,7 @@ class HomeModel(
return application.packageManager
.getInstalledPackages(PackageManager.GET_META_DATA)
.filter {
// Shiggy doesn't have "legacy installer" whatsoever
// Goon doesn't have "legacy installer" whatsoever
return@filter it.applicationInfo?.metaData?.containsKey("isShiggy") == true
// // Packages installed via the legacy Installer do not have the metadata marker
@ -281,11 +318,11 @@ class HomeModel(
}
/**
* Checks whether the current Shiggy installation is up-to-date.
* Checks whether the current Goon installation is up-to-date.
*
* Currently mirrors the behavior of Bunny Manager by directly comparing against
* the latest available Discord and ShiggyXposed release. This is a temporary approach and will remain
* in place until Shiggy adds support for version pinning.
* the latest available Discord and GoonXposed release. This is a temporary approach and will remain
* in place until Goon adds support for version pinning.
*/
private fun isInstallationUpToDate(pkg: PackageInfo): Boolean? {
val trackerData = trackerIndexJson ?: return null
@ -297,7 +334,7 @@ class HomeModel(
// Try to parse install metadata. If none present, install was made via legacy installer.
val apkPath = pkg.applicationInfo?.publicSourceDir ?: return false
val installMetadata = try {
val metadataFile = ZipReader(apkPath).use { it.openEntry("shiggy.json")?.read() }
val metadataFile = ZipReader(apkPath).use { it.openEntry("goon.json")?.read() }
?: return false
@OptIn(ExperimentalSerializationApi::class)
@ -314,6 +351,6 @@ class HomeModel(
VersionPreference.Custom -> return true
}
return latestByPref == versionCode && installMetadata.shiggyXposedVersion == latestShiggyXposedVersion
return latestByPref == versionCode && installMetadata.goonXposedVersion == latestGoonXposedVersion
}
}

View file

@ -30,11 +30,10 @@ import com.aliucord.manager.ui.components.LoadFailure
import com.aliucord.manager.ui.components.ProjectHeader
import com.aliucord.manager.ui.screens.home.components.*
import com.aliucord.manager.ui.screens.patchopts.PatchOptionsScreen
import com.aliucord.manager.ui.screens.plugins.PluginsScreen
import com.aliucord.manager.ui.util.paddings.PaddingValuesSides
import com.aliucord.manager.ui.util.paddings.exclude
import com.aliucord.manager.util.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
@ -78,7 +77,6 @@ class HomeScreen : Screen, Parcelable {
},
onOpenApp = model::openApp,
onOpenAppInfo = model::openAppInfo,
onOpenPlugins = { navigator.push(PluginsScreen()) }, // TODO: install-specific plugins
onUninstall = model::uninstallApp,
)
@ -129,7 +127,6 @@ fun HomeScreenLoadedContent(
onUpdate: (packageName: String) -> Unit,
onOpenApp: (packageName: String) -> Unit,
onOpenAppInfo: (packageName: String) -> Unit,
onOpenPlugins: (packageName: String) -> Unit,
onUninstall: (packageName: String) -> Unit,
) {
LazyColumn(
@ -163,7 +160,6 @@ fun HomeScreenLoadedContent(
onUpdate = { onUpdate(item.packageName) },
onOpenApp = { onOpenApp(item.packageName) },
onOpenInfo = { onOpenAppInfo(item.packageName) },
onOpenPlugins = { onOpenPlugins(item.packageName) },
onUninstall = { onUninstall(item.packageName) },
modifier = Modifier.fillMaxWidth()
)

View file

@ -8,7 +8,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
import com.aliucord.manager.ui.screens.about.AboutScreen
import com.aliucord.manager.ui.screens.logs.LogsListScreen
import com.aliucord.manager.ui.screens.settings.SettingsScreen
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun HomeAppBar() {

View file

@ -14,7 +14,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.aliucord.manager.ui.util.thenIf
import com.valentinilk.shimmer.*
import dev.shiggy.manager.R
import dev.goon.manager.R
private val shimmerTheme = defaultShimmerTheme.copy(
shimmerWidth = 150.dp,

View file

@ -18,7 +18,7 @@ import androidx.compose.ui.unit.dp
import com.aliucord.manager.ui.components.SegmentedButton
import com.aliucord.manager.ui.components.VersionDisplay
import com.aliucord.manager.ui.screens.home.InstallData
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun InstalledItemCard(
@ -26,7 +26,6 @@ fun InstalledItemCard(
onUpdate: () -> Unit,
onOpenApp: () -> Unit,
onOpenInfo: () -> Unit,
onOpenPlugins: () -> Unit,
onUninstall: () -> Unit,
modifier: Modifier = Modifier,
) {
@ -89,13 +88,6 @@ fun InstalledItemCard(
horizontalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier.clip(MaterialTheme.shapes.large),
) {
// // Plugins cannot be managed externally yet in Shiggy
// SegmentedButton(
// icon = painterResource(R.drawable.ic_extension),
// text = stringResource(R.string.plugins_title),
// onClick = onOpenPlugins,
// )
// If the up-to-date status cannot be determined, assume it is up-to-date
if (data.isUpToDate != false)
SegmentedButton(
@ -126,7 +118,7 @@ fun InstalledItemCard(
)
SegmentedButton(
icon = painterResource(R.drawable.ic_delete_forever),
text = stringResource(R.string.action_uninstall), // Assuming R.string.action_uninstall exists or will be added
text = stringResource(R.string.action_uninstall),
iconColor = MaterialTheme.colorScheme.error,
textColor = MaterialTheme.colorScheme.error,
onClick = onUninstall,

View file

@ -10,8 +10,8 @@ import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import com.aliucord.manager.ui.screens.patchopts.PatchOptions.IconReplacement
import com.aliucord.manager.util.*
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
import dev.zt64.compose.pipette.HsvColor
import java.io.IOException

View file

@ -41,7 +41,7 @@ import com.aliucord.manager.ui.screens.patchopts.PatchOptionsScreen
import com.aliucord.manager.ui.util.ColorSaver
import com.aliucord.manager.ui.util.throttledState
import com.aliucord.manager.util.back
import dev.shiggy.manager.R
import dev.goon.manager.R
import dev.zt64.compose.pipette.CircularColorPicker
import dev.zt64.compose.pipette.HsvColor
import kotlinx.parcelize.IgnoredOnParcel

View file

@ -7,7 +7,7 @@ import androidx.compose.ui.res.stringResource
import cafe.adriel.voyager.navigator.LocalNavigator
import com.aliucord.manager.ui.components.BackButton
import com.aliucord.manager.ui.screens.settings.SettingsScreen
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun IconOptionsAppBar() {

View file

@ -11,7 +11,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import dev.shiggy.manager.R
import dev.goon.manager.R
import java.util.Locale
import kotlin.math.roundToInt

View file

@ -18,7 +18,7 @@ import com.aliucord.manager.ui.components.Label
import com.aliucord.manager.ui.screens.log.components.LogAppBar
import com.aliucord.manager.ui.screens.log.components.LogTextArea
import com.aliucord.manager.util.back
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import org.koin.core.parameter.parametersOf

View file

@ -10,8 +10,8 @@ import cafe.adriel.voyager.core.model.screenModelScope
import com.aliucord.manager.manager.InstallLogData
import com.aliucord.manager.manager.InstallLogManager
import com.aliucord.manager.util.*
import dev.shiggy.manager.BuildConfig
import dev.shiggy.manager.R
import dev.goon.manager.BuildConfig
import dev.goon.manager.R
class LogScreenModel(
private val installId: String,

View file

@ -5,7 +5,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.aliucord.manager.ui.components.BackButton
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun LogAppBar(

View file

@ -8,7 +8,7 @@ import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import com.aliucord.manager.manager.InstallLogManager
import com.aliucord.manager.util.*
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

View file

@ -21,7 +21,7 @@ import com.aliucord.manager.patcher.steps.base.StepState
import com.aliucord.manager.ui.screens.logs.LogEntry
import com.aliucord.manager.ui.screens.patching.components.StepStateIcon
import com.aliucord.manager.ui.screens.patching.components.TimeElapsed
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun LogEntryCard(

View file

@ -7,7 +7,7 @@ import androidx.compose.ui.res.stringResource
import cafe.adriel.voyager.navigator.LocalNavigator
import com.aliucord.manager.ui.components.BackButton
import com.aliucord.manager.ui.screens.settings.SettingsScreen
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun LogsListAppBar(

View file

@ -9,7 +9,7 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun LogsNone(modifier: Modifier = Modifier) {

View file

@ -8,7 +8,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import dev.shiggy.manager.R
import dev.goon.manager.R
@Composable
fun DeleteLogsDialog(

View file

@ -40,7 +40,7 @@ import com.aliucord.manager.ui.util.spacedByLastAtBottom
import com.aliucord.manager.ui.util.thenIf
import com.aliucord.manager.util.back
import com.aliucord.manager.util.isIgnoringBatteryOptimizations
import dev.shiggy.manager.R
import dev.goon.manager.R
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.filter
import kotlinx.parcelize.IgnoredOnParcel

Some files were not shown because too many files have changed in this diff Show more